From 42de4514deffc5a5fec9b63fa6a74b603b314185 Mon Sep 17 00:00:00 2001 From: Carter McBride <18412686+carterworks@users.noreply.github.com> Date: Thu, 11 Dec 2025 20:35:54 -0700 Subject: [PATCH 01/56] Create a licensing eslint plugin --- .husky/pre-commit | 1 - eslint.config.js | 24 ++++ package.json | 5 +- pnpm-lock.yaml | 44 -------- scripts/add-license.js | 122 -------------------- scripts/eslint/eslintLicensePlugin.js | 141 ++++++++++++++++++++++++ scripts/source-header.handlebars | 11 -- scripts/specs/licenseHeaderRule.spec.js | 96 ++++++++++++++++ scripts/testConvert.js | 12 ++ 9 files changed, 274 insertions(+), 182 deletions(-) delete mode 100755 scripts/add-license.js create mode 100644 scripts/eslint/eslintLicensePlugin.js delete mode 100644 scripts/source-header.handlebars create mode 100644 scripts/specs/licenseHeaderRule.spec.js diff --git a/.husky/pre-commit b/.husky/pre-commit index 960e12f63..6b498b32d 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1,4 +1,3 @@ -STAGED_ONLY=true npm run add-license npx lint-staged npm run test:scripts npm run test:unit diff --git a/eslint.config.js b/eslint.config.js index c37b81c9e..80f8f9180 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -19,6 +19,8 @@ import react from "eslint-plugin-react"; import { defineConfig, globalIgnores } from "eslint/config"; import { glob } from "glob"; import globals from "globals"; +// eslint-disable-next-line import/extensions +import licensePlugin from "./scripts/eslint/eslintLicensePlugin.js"; const allComponentPaths = glob.sync("packages/core/src/components/*/"); @@ -31,7 +33,29 @@ export default defineConfig([ "sandboxes/**/build/", "sandboxes/**/public/", "node_modules/", + "launch*.js", ]), + { + name: "alloy/license-header", + files: ["**/*.{cjs,js,mjs,jsx}"], + ignores: [ + "sandboxes/**", + "dist/**", + "distTest/**", + "packages/**/dist/**", + "packages/**/distTest/**", + "launch*.js", + "**/*.min.js", + "**/at.js", + "**/*AppMeasurement*", + ], + plugins: { + alloy: licensePlugin, + }, + rules: { + "alloy/license-header": "error", + }, + }, { name: "alloy/shared", languageOptions: { diff --git a/package.json b/package.json index 72461754d..1cd8e8ffa 100644 --- a/package.json +++ b/package.json @@ -49,8 +49,7 @@ "build:custom": "node scripts/alloyBuilder.js", "prepare": "husky", "prepack": "pnpm run clean && babel packages/core/src -d libEs5 --env-name npmEs5 && babel packages/core/src -d libEs6 --env-name npmEs6 && echo '{\"type\":\"commonjs\"}' > libEs5/package.json && echo '{\"type\":\"module\"}' > libEs6/package.json && pnpm run types", - "checkthattestfilesexist": "./scripts/checkThatTestFilesExist.js", - "add-license": "./scripts/add-license.js" + "checkthattestfilesexist": "./scripts/checkThatTestFilesExist.js" }, "lint-staged": { "./*.{cjs,mjs,js,jsx}": [ @@ -110,7 +109,6 @@ "eslint-plugin-react": "^7.37.5", "glob": "^11.0.3", "globals": "^16.5.0", - "handlebars": "^4.7.8", "husky": "^9.1.7", "lint-staged": "^16.2.6", "minimatch": "^10.1.1", @@ -121,7 +119,6 @@ "recursive-readdir": "^2.2.3", "rimraf": "^6.1.0", "semver": "^7.7.3", - "staged-git-files": "^1.3.0", "testcafe": "^3.7.2", "testcafe-browser-provider-playwright": "^1.1.0", "typescript": "^5.9.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4af38481e..2da770cb5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -114,9 +114,6 @@ importers: globals: specifier: ^16.5.0 version: 16.5.0 - handlebars: - specifier: ^4.7.8 - version: 4.7.8 husky: specifier: ^9.1.7 version: 9.1.7 @@ -147,9 +144,6 @@ importers: semver: specifier: ^7.7.3 version: 7.7.3 - staged-git-files: - specifier: ^1.3.0 - version: 1.3.0 testcafe: specifier: ^3.7.2 version: 3.7.2 @@ -2649,11 +2643,6 @@ packages: resolution: {integrity: sha512-mS1lbMsxgQj6hge1XZ6p7GPhbrtFwUFYi3wRzXAC/FmYnyXMTvvI3td3rjmQ2u8ewXueaSvRPWaEcgVVOT9Jnw==} engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0} - handlebars@4.7.8: - resolution: {integrity: sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==} - engines: {node: '>=0.4.7'} - hasBin: true - happy-dom@20.0.8: resolution: {integrity: sha512-TlYaNQNtzsZ97rNMBAm8U+e2cUQXNithgfCizkDgc11lgmN4j9CKMhO3FPGKWQYPwwkFcPpoXYF/CqEPLgzfOg==} engines: {node: '>=20.0.0'} @@ -3251,9 +3240,6 @@ packages: natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} - neo-async@2.6.2: - resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} - node-releases@2.0.21: resolution: {integrity: sha512-5b0pgg78U3hwXkCM8Z9b2FJdPZlr9Psr9V2gQPESdGHqbntyFJKFW4r5TeWGFzafGY3hzs1JC62VEQMbl1JFkw==} @@ -3884,10 +3870,6 @@ packages: stackframe@1.3.4: resolution: {integrity: sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==} - staged-git-files@1.3.0: - resolution: {integrity: sha512-38Kd8VBVMVqtuavWAzwV9uWvbIhTQh0hNWMWzj2FAOjdMHgLJOArE3eYBSbLgV28j4F3AXieOMekFqM9UX6wxw==} - hasBin: true - statuses@2.0.2: resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==} engines: {node: '>= 0.8'} @@ -4150,11 +4132,6 @@ packages: engines: {node: '>=14.17'} hasBin: true - uglify-js@3.19.3: - resolution: {integrity: sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==} - engines: {node: '>=0.8.0'} - hasBin: true - unbox-primitive@1.1.0: resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} engines: {node: '>= 0.4'} @@ -4352,9 +4329,6 @@ packages: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} engines: {node: '>=0.10.0'} - wordwrap@1.0.0: - resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==} - wrap-ansi@6.2.0: resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} engines: {node: '>=8'} @@ -7227,15 +7201,6 @@ snapshots: graphql@16.11.0: {} - handlebars@4.7.8: - dependencies: - minimist: 1.2.8 - neo-async: 2.6.2 - source-map: 0.6.1 - wordwrap: 1.0.0 - optionalDependencies: - uglify-js: 3.19.3 - happy-dom@20.0.8: dependencies: '@types/node': 20.19.22 @@ -7798,8 +7763,6 @@ snapshots: natural-compare@1.4.0: {} - neo-async@2.6.2: {} - node-releases@2.0.21: {} normalize-path@3.0.0: @@ -8439,8 +8402,6 @@ snapshots: stackframe@1.3.4: {} - staged-git-files@1.3.0: {} - statuses@2.0.2: {} std-env@3.9.0: {} @@ -8880,9 +8841,6 @@ snapshots: typescript@5.9.3: {} - uglify-js@3.19.3: - optional: true - unbox-primitive@1.1.0: dependencies: call-bound: 1.0.4 @@ -9068,8 +9026,6 @@ snapshots: word-wrap@1.2.5: {} - wordwrap@1.0.0: {} - wrap-ansi@6.2.0: dependencies: ansi-styles: 4.3.0 diff --git a/scripts/add-license.js b/scripts/add-license.js deleted file mode 100755 index b88f3098f..000000000 --- a/scripts/add-license.js +++ /dev/null @@ -1,122 +0,0 @@ -#!/usr/bin/env node - -/* -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 fs from "fs"; -import stagedGitFiles from "staged-git-files"; -import Handlebars from "handlebars"; -import { getDirname, getProjectRoot, safePathJoin } from "./helpers/path.js"; - -const dirname = getDirname(import.meta.url); - -const PROJECT_ROOT = getProjectRoot(); -const SOURCE_TEMPLATE = "source-header.handlebars"; - -const GIT_DELETED = "Deleted"; -const SOURCE_FILE_EXTENSIONS = ["js", "ts", "cjs", "mjs"]; -const IGNORE_PATTERNS = [ - /\/sandboxes\//gi, - /\/scripts\//gi, - /launch.+\.js/gi, - /at\.js/gi, - /\.min\.js/gi, - /AppMeasurement/gi, -]; - -const walk = async (dir, matchesFilter) => { - let files = fs.readdirSync(dir); - files = await Promise.all( - files - .filter((file) => matchesFilter(file, dir)) - .map(async (file) => { - const filePath = safePathJoin(dir, file); - const stats = fs.statSync(filePath); - if (stats.isDirectory()) { - return walk(filePath, matchesFilter); - } - return filePath; - }), - ); - - return files.reduce((all, folderContents) => all.concat(folderContents), []); -}; - -const getStagedGitFiles = async () => { - return (await stagedGitFiles()) - .filter((detail) => { - const parts = detail.filename.split("."); - return ( - detail.status !== GIT_DELETED && - parts.length > 1 && - SOURCE_FILE_EXTENSIONS.indexOf(parts[1]) > -1 - ); - }) - .map((detail) => safePathJoin(PROJECT_ROOT, detail.filename)); -}; - -const getAllSourceFiles = async () => { - const IGNORED = ["node_modules", ".git", "dist"]; - return walk(PROJECT_ROOT, (file, dir) => { - const filePath = safePathJoin(dir, file); - const stats = fs.statSync(filePath); - - for (let i = 0; i < IGNORED.length; i += 1) { - if (filePath.includes(IGNORED[i])) { - return false; - } - } - - if (stats.isDirectory()) { - return true; - } - - if (stats.isFile()) { - for (let i = 0; i < SOURCE_FILE_EXTENSIONS.length; i += 1) { - if (file.endsWith(SOURCE_FILE_EXTENSIONS[i])) { - return true; - } - } - } - - return false; - }); -}; - -const run = async () => { - const stagedOnly = typeof process.env.STAGED_ONLY !== "undefined"; - - const template = fs.readFileSync( - safePathJoin(dirname, SOURCE_TEMPLATE), - "utf-8", - ); - - const renderTemplate = Handlebars.compile(template); - - const templateText = renderTemplate({ - year: new Date().getFullYear(), - }); - - const sourceFiles = stagedOnly - ? await getStagedGitFiles() - : await getAllSourceFiles(); - - sourceFiles - .filter((file) => IGNORE_PATTERNS.every((pattern) => !file.match(pattern))) - .forEach((file) => { - const contents = fs.readFileSync(safePathJoin(file), "utf-8"); - if (templateText.slice(0, 2) !== contents.slice(0, 2)) { - fs.writeFileSync(safePathJoin(file), `${templateText}${contents}`); - } - }); -}; - -run(); diff --git a/scripts/eslint/eslintLicensePlugin.js b/scripts/eslint/eslintLicensePlugin.js new file mode 100644 index 000000000..8357767a2 --- /dev/null +++ b/scripts/eslint/eslintLicensePlugin.js @@ -0,0 +1,141 @@ +/* +Copyright 2025 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. +*/ + +const COPYRIGHT_LINE_REGEX = + /Copyright\s+\d{4}\s+Adobe\. All rights reserved\./; +const REQUIRED_SUBSTRINGS = [ + 'Apache License, Version 2.0 (the "License")', + "http://www.apache.org/licenses/LICENSE-2.0", + "governing permissions and limitations under the License.", +]; + +const SOURCE_HEADER_TEMPLATE = `/* +Copyright {{year}} 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. +*/`; + +const renderHeader = (year) => { + return SOURCE_HEADER_TEMPLATE.replace("{{year}}", String(year)).trimEnd(); +}; + +const startsWithBom = (text) => text.startsWith("\uFEFF"); + +const getShebangEndIndex = (text) => { + if (!text.startsWith("#!")) { + return 0; + } + const newlineIndex = text.indexOf("\n"); + return newlineIndex === -1 ? text.length : newlineIndex + 1; +}; + +const getLeadingWhitespaceLength = (text) => { + const match = text.match(/^[\t \r\n]*/); + return match ? match[0].length : 0; +}; + +const hasLicenseHeaderAtStart = (text) => { + if (!text.startsWith("/*")) { + return false; + } + const endIndex = text.indexOf("*/"); + if (endIndex === -1) { + return false; + } + const comment = text.slice(0, endIndex + 2); + if (!COPYRIGHT_LINE_REGEX.test(comment)) { + return false; + } + return REQUIRED_SUBSTRINGS.every((s) => comment.includes(s)); +}; + +const licenseHeaderRule = { + meta: { + type: "layout", + docs: { + description: + "Require the Apache license header at the top of source files.", + }, + fixable: "code", + schema: [ + { + type: "object", + additionalProperties: false, + properties: { + year: { + type: "integer", + }, + }, + }, + ], + messages: { + missing: "Missing Apache license header.", + }, + }, + create(context) { + const sourceCode = context.getSourceCode(); + + return { + Program(node) { + const originalText = sourceCode.getText(); + const bomOffset = startsWithBom(originalText) ? 1 : 0; + const text = originalText.slice(bomOffset); + + const shebangEnd = getShebangEndIndex(text); + const afterShebang = text.slice(shebangEnd); + const leadingWhitespaceLength = + getLeadingWhitespaceLength(afterShebang); + const checkStart = shebangEnd + leadingWhitespaceLength; + + if (hasLicenseHeaderAtStart(text.slice(checkStart))) { + return; + } + + context.report({ + node, + loc: { line: 1, column: 0 }, + messageId: "missing", + fix(fixer) { + const year = context.options?.[0]?.year ?? new Date().getFullYear(); + const headerBlock = renderHeader(year); + + const replacement = + shebangEnd > 0 ? `\n${headerBlock}\n\n` : `${headerBlock}\n\n`; + + const replaceStart = bomOffset + shebangEnd; + const replaceEnd = replaceStart + leadingWhitespaceLength; + return fixer.replaceTextRange( + [replaceStart, replaceEnd], + replacement, + ); + }, + }); + }, + }; + }, +}; + +export default { + meta: { + name: "alloy", + version: "local", + }, + rules: { + "license-header": licenseHeaderRule, + }, +}; diff --git a/scripts/source-header.handlebars b/scripts/source-header.handlebars deleted file mode 100644 index d806b820a..000000000 --- a/scripts/source-header.handlebars +++ /dev/null @@ -1,11 +0,0 @@ -/* -Copyright {{year}} 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. -*/ diff --git a/scripts/specs/licenseHeaderRule.spec.js b/scripts/specs/licenseHeaderRule.spec.js new file mode 100644 index 000000000..d7b1d317c --- /dev/null +++ b/scripts/specs/licenseHeaderRule.spec.js @@ -0,0 +1,96 @@ +/* +Copyright 2025 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 { RuleTester } from "eslint"; +import { + afterAll, + afterEach, + beforeAll, + beforeEach, + describe, + it, +} from "vitest"; +import alloyPlugin from "../eslint/eslintLicensePlugin.js"; + +RuleTester.afterAll = afterAll; +RuleTester.afterEach = afterEach; +RuleTester.beforeAll = beforeAll; +RuleTester.beforeEach = beforeEach; +RuleTester.describe = describe; +RuleTester.it = it; + +const ruleTester = new RuleTester({ + languageOptions: { + ecmaVersion: "latest", + sourceType: "module", + }, +}); + +const rule = alloyPlugin.rules["license-header"]; + +const HEADER_2000 = `/* +Copyright 2000 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. +*/`; + +ruleTester.run("license-header", rule, { + valid: [ + { + code: `${HEADER_2000}\n\nimport foo from "foo";`, + options: [{ year: 2000 }], + }, + { + code: `#!/usr/bin/env node\n\n${HEADER_2000}\n\nconsole.log("hi");`, + options: [{ year: 2000 }], + }, + // Some historical files omit the blank line after the License URL. + { + code: `/* +Copyright 2000 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. +*/\n\nexport default 1;`, + }, + ], + invalid: [ + { + code: `import foo from "foo";`, + options: [{ year: 2000 }], + errors: [{ messageId: "missing" }], + output: `${HEADER_2000}\n\nimport foo from "foo";`, + }, + { + code: `/* eslint-disable no-console */\nconsole.log("hi");`, + options: [{ year: 2000 }], + errors: [{ messageId: "missing" }], + output: `${HEADER_2000}\n\n/* eslint-disable no-console */\nconsole.log("hi");`, + }, + { + code: `#!/usr/bin/env node\n\nconsole.log("hi");`, + options: [{ year: 2000 }], + errors: [{ messageId: "missing" }], + output: `#!/usr/bin/env node\n\n${HEADER_2000}\n\nconsole.log("hi");`, + }, + ], +}); diff --git a/scripts/testConvert.js b/scripts/testConvert.js index 326b1f572..82ea9f8dc 100755 --- a/scripts/testConvert.js +++ b/scripts/testConvert.js @@ -1,5 +1,17 @@ #!/usr/bin/env node +/* +Copyright 2025 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 { execSync as exec } from "child_process"; import fs from "fs"; import path from "path"; From cae54e8f23df28a0908156c046290ec3dd1f5512 Mon Sep 17 00:00:00 2001 From: Carter McBride <18412686+carterworks@users.noreply.github.com> Date: Fri, 12 Dec 2025 08:47:26 -0700 Subject: [PATCH 02/56] Convert license inclusion script to eslint plugin --- .../handlers/onBeforeSendEventHandler.js | 10 +- .../handlers/viewThroughHandler.js | 10 +- .../Advertising/identities/collectSurferId.js | 9 +- scripts/eslint/alloy-eslint-plugin.js | 141 ++++++++++++++++++ scripts/helpers/path.js | 12 ++ scripts/helpers/versionBabelPlugin.js | 12 ++ scripts/specs/vitest.config.js | 12 ++ 7 files changed, 201 insertions(+), 5 deletions(-) create mode 100644 scripts/eslint/alloy-eslint-plugin.js diff --git a/packages/core/src/components/Advertising/handlers/onBeforeSendEventHandler.js b/packages/core/src/components/Advertising/handlers/onBeforeSendEventHandler.js index 81ebdc709..ccfd0fad6 100644 --- a/packages/core/src/components/Advertising/handlers/onBeforeSendEventHandler.js +++ b/packages/core/src/components/Advertising/handlers/onBeforeSendEventHandler.js @@ -1,7 +1,13 @@ /* Copyright 2023 Adobe. All rights reserved. -Licensed under the Apache License, Version 2.0. -http://www.apache.org/licenses/LICENSE-2.0 +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 collectSurferId from "../identities/collectSurferId.js"; diff --git a/packages/core/src/components/Advertising/handlers/viewThroughHandler.js b/packages/core/src/components/Advertising/handlers/viewThroughHandler.js index 9483a1242..55b8e63ce 100644 --- a/packages/core/src/components/Advertising/handlers/viewThroughHandler.js +++ b/packages/core/src/components/Advertising/handlers/viewThroughHandler.js @@ -1,7 +1,13 @@ /* Copyright 2025 Adobe. All rights reserved. -Licensed under the Apache License, Version 2.0. -http://www.apache.org/licenses/LICENSE-2.0 +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 collectAllIdentities from "../identities/collectAllIdentities.js"; diff --git a/packages/core/src/components/Advertising/identities/collectSurferId.js b/packages/core/src/components/Advertising/identities/collectSurferId.js index 17d887523..e5c6a1a61 100644 --- a/packages/core/src/components/Advertising/identities/collectSurferId.js +++ b/packages/core/src/components/Advertising/identities/collectSurferId.js @@ -1,6 +1,13 @@ /* Copyright 2025 Adobe. All rights reserved. -This file is licensed under the Apache License, Version 2.0. +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 { diff --git a/scripts/eslint/alloy-eslint-plugin.js b/scripts/eslint/alloy-eslint-plugin.js new file mode 100644 index 000000000..8357767a2 --- /dev/null +++ b/scripts/eslint/alloy-eslint-plugin.js @@ -0,0 +1,141 @@ +/* +Copyright 2025 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. +*/ + +const COPYRIGHT_LINE_REGEX = + /Copyright\s+\d{4}\s+Adobe\. All rights reserved\./; +const REQUIRED_SUBSTRINGS = [ + 'Apache License, Version 2.0 (the "License")', + "http://www.apache.org/licenses/LICENSE-2.0", + "governing permissions and limitations under the License.", +]; + +const SOURCE_HEADER_TEMPLATE = `/* +Copyright {{year}} 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. +*/`; + +const renderHeader = (year) => { + return SOURCE_HEADER_TEMPLATE.replace("{{year}}", String(year)).trimEnd(); +}; + +const startsWithBom = (text) => text.startsWith("\uFEFF"); + +const getShebangEndIndex = (text) => { + if (!text.startsWith("#!")) { + return 0; + } + const newlineIndex = text.indexOf("\n"); + return newlineIndex === -1 ? text.length : newlineIndex + 1; +}; + +const getLeadingWhitespaceLength = (text) => { + const match = text.match(/^[\t \r\n]*/); + return match ? match[0].length : 0; +}; + +const hasLicenseHeaderAtStart = (text) => { + if (!text.startsWith("/*")) { + return false; + } + const endIndex = text.indexOf("*/"); + if (endIndex === -1) { + return false; + } + const comment = text.slice(0, endIndex + 2); + if (!COPYRIGHT_LINE_REGEX.test(comment)) { + return false; + } + return REQUIRED_SUBSTRINGS.every((s) => comment.includes(s)); +}; + +const licenseHeaderRule = { + meta: { + type: "layout", + docs: { + description: + "Require the Apache license header at the top of source files.", + }, + fixable: "code", + schema: [ + { + type: "object", + additionalProperties: false, + properties: { + year: { + type: "integer", + }, + }, + }, + ], + messages: { + missing: "Missing Apache license header.", + }, + }, + create(context) { + const sourceCode = context.getSourceCode(); + + return { + Program(node) { + const originalText = sourceCode.getText(); + const bomOffset = startsWithBom(originalText) ? 1 : 0; + const text = originalText.slice(bomOffset); + + const shebangEnd = getShebangEndIndex(text); + const afterShebang = text.slice(shebangEnd); + const leadingWhitespaceLength = + getLeadingWhitespaceLength(afterShebang); + const checkStart = shebangEnd + leadingWhitespaceLength; + + if (hasLicenseHeaderAtStart(text.slice(checkStart))) { + return; + } + + context.report({ + node, + loc: { line: 1, column: 0 }, + messageId: "missing", + fix(fixer) { + const year = context.options?.[0]?.year ?? new Date().getFullYear(); + const headerBlock = renderHeader(year); + + const replacement = + shebangEnd > 0 ? `\n${headerBlock}\n\n` : `${headerBlock}\n\n`; + + const replaceStart = bomOffset + shebangEnd; + const replaceEnd = replaceStart + leadingWhitespaceLength; + return fixer.replaceTextRange( + [replaceStart, replaceEnd], + replacement, + ); + }, + }); + }, + }; + }, +}; + +export default { + meta: { + name: "alloy", + version: "local", + }, + rules: { + "license-header": licenseHeaderRule, + }, +}; diff --git a/scripts/helpers/path.js b/scripts/helpers/path.js index 74518b9ec..3c70074c8 100644 --- a/scripts/helpers/path.js +++ b/scripts/helpers/path.js @@ -1,3 +1,15 @@ +/* +Copyright 2025 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 path from "path"; import process from "process"; import { fileURLToPath } from "url"; diff --git a/scripts/helpers/versionBabelPlugin.js b/scripts/helpers/versionBabelPlugin.js index 49819c6a6..f15d3777a 100644 --- a/scripts/helpers/versionBabelPlugin.js +++ b/scripts/helpers/versionBabelPlugin.js @@ -1,3 +1,15 @@ +/* +Copyright 2025 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 { createRequire } from "module"; const require = createRequire(import.meta.url); diff --git a/scripts/specs/vitest.config.js b/scripts/specs/vitest.config.js index 7469bf6fd..03bb6bb6d 100644 --- a/scripts/specs/vitest.config.js +++ b/scripts/specs/vitest.config.js @@ -1,3 +1,15 @@ +/* +Copyright 2025 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. +*/ + // eslint-disable-next-line import/no-unresolved import { defineProject } from "vitest/config"; From c2e02fff0fd74cfe93847433b61410e35fd80838 Mon Sep 17 00:00:00 2001 From: Carter McBride <18412686+carterworks@users.noreply.github.com> Date: Fri, 12 Dec 2025 09:24:38 -0700 Subject: [PATCH 03/56] Use the license_banner for the eslint plugin. --- scripts/eslint/eslintLicensePlugin.js | 34 +++++++++++++++++-------- scripts/specs/licenseHeaderRule.spec.js | 22 +++++++++------- 2 files changed, 36 insertions(+), 20 deletions(-) diff --git a/scripts/eslint/eslintLicensePlugin.js b/scripts/eslint/eslintLicensePlugin.js index 8357767a2..00db55402 100644 --- a/scripts/eslint/eslintLicensePlugin.js +++ b/scripts/eslint/eslintLicensePlugin.js @@ -10,6 +10,10 @@ OF ANY KIND, either express or implied. See the License for the specific languag governing permissions and limitations under the License. */ +import fs from "fs"; +import path from "path"; +import { fileURLToPath } from "url"; + const COPYRIGHT_LINE_REGEX = /Copyright\s+\d{4}\s+Adobe\. All rights reserved\./; const REQUIRED_SUBSTRINGS = [ @@ -18,20 +22,28 @@ const REQUIRED_SUBSTRINGS = [ "governing permissions and limitations under the License.", ]; -const SOURCE_HEADER_TEMPLATE = `/* -Copyright {{year}} 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 +const dirname = path.dirname(fileURLToPath(import.meta.url)); +const LICENSE_BANNER_PATH = path.resolve(dirname, "../../LICENSE_BANNER"); -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. -*/`; +let licenseBannerBodyCache; +const getLicenseBannerBody = () => { + if (licenseBannerBodyCache) { + return licenseBannerBodyCache; + } + + // LICENSE_BANNER is used for bundles, so we reuse it as the single source of truth + // for the license text and keep only the *year* file-specific. + const bannerText = fs.readFileSync(LICENSE_BANNER_PATH, "utf-8").trimEnd(); + const lines = bannerText.split(/\r?\n/); + licenseBannerBodyCache = lines.slice(1).join("\n"); + return licenseBannerBodyCache; +}; const renderHeader = (year) => { - return SOURCE_HEADER_TEMPLATE.replace("{{year}}", String(year)).trimEnd(); + return `/* +Copyright ${String(year)} Adobe. All rights reserved. +${getLicenseBannerBody()} +*/`.trimEnd(); }; const startsWithBom = (text) => text.startsWith("\uFEFF"); diff --git a/scripts/specs/licenseHeaderRule.spec.js b/scripts/specs/licenseHeaderRule.spec.js index d7b1d317c..54acd863d 100644 --- a/scripts/specs/licenseHeaderRule.spec.js +++ b/scripts/specs/licenseHeaderRule.spec.js @@ -10,6 +10,8 @@ OF ANY KIND, either express or implied. See the License for the specific languag governing permissions and limitations under the License. */ +import fs from "fs"; +import path from "path"; import { RuleTester } from "eslint"; import { afterAll, @@ -37,18 +39,20 @@ const ruleTester = new RuleTester({ const rule = alloyPlugin.rules["license-header"]; -const HEADER_2000 = `/* -Copyright 2000 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 +const LICENSE_BANNER_PATH = path.resolve(process.cwd(), "LICENSE_BANNER"); +const getLicenseBannerBody = () => { + const bannerText = fs.readFileSync(LICENSE_BANNER_PATH, "utf-8").trimEnd(); + const lines = bannerText.split(/\r?\n/); + return lines.slice(1).join("\n"); +}; -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. +const buildHeader = (year) => `/* +Copyright ${String(year)} Adobe. All rights reserved. +${getLicenseBannerBody()} */`; +const HEADER_2000 = buildHeader(2000); + ruleTester.run("license-header", rule, { valid: [ { From 2a3b73fa59e726672397995023296fd475f9968d Mon Sep 17 00:00:00 2001 From: Carter McBride <18412686+carterworks@users.noreply.github.com> Date: Fri, 12 Dec 2025 09:41:30 -0700 Subject: [PATCH 04/56] Delete old file --- scripts/eslint/alloy-eslint-plugin.js | 141 -------------------------- 1 file changed, 141 deletions(-) delete mode 100644 scripts/eslint/alloy-eslint-plugin.js diff --git a/scripts/eslint/alloy-eslint-plugin.js b/scripts/eslint/alloy-eslint-plugin.js deleted file mode 100644 index 8357767a2..000000000 --- a/scripts/eslint/alloy-eslint-plugin.js +++ /dev/null @@ -1,141 +0,0 @@ -/* -Copyright 2025 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. -*/ - -const COPYRIGHT_LINE_REGEX = - /Copyright\s+\d{4}\s+Adobe\. All rights reserved\./; -const REQUIRED_SUBSTRINGS = [ - 'Apache License, Version 2.0 (the "License")', - "http://www.apache.org/licenses/LICENSE-2.0", - "governing permissions and limitations under the License.", -]; - -const SOURCE_HEADER_TEMPLATE = `/* -Copyright {{year}} 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. -*/`; - -const renderHeader = (year) => { - return SOURCE_HEADER_TEMPLATE.replace("{{year}}", String(year)).trimEnd(); -}; - -const startsWithBom = (text) => text.startsWith("\uFEFF"); - -const getShebangEndIndex = (text) => { - if (!text.startsWith("#!")) { - return 0; - } - const newlineIndex = text.indexOf("\n"); - return newlineIndex === -1 ? text.length : newlineIndex + 1; -}; - -const getLeadingWhitespaceLength = (text) => { - const match = text.match(/^[\t \r\n]*/); - return match ? match[0].length : 0; -}; - -const hasLicenseHeaderAtStart = (text) => { - if (!text.startsWith("/*")) { - return false; - } - const endIndex = text.indexOf("*/"); - if (endIndex === -1) { - return false; - } - const comment = text.slice(0, endIndex + 2); - if (!COPYRIGHT_LINE_REGEX.test(comment)) { - return false; - } - return REQUIRED_SUBSTRINGS.every((s) => comment.includes(s)); -}; - -const licenseHeaderRule = { - meta: { - type: "layout", - docs: { - description: - "Require the Apache license header at the top of source files.", - }, - fixable: "code", - schema: [ - { - type: "object", - additionalProperties: false, - properties: { - year: { - type: "integer", - }, - }, - }, - ], - messages: { - missing: "Missing Apache license header.", - }, - }, - create(context) { - const sourceCode = context.getSourceCode(); - - return { - Program(node) { - const originalText = sourceCode.getText(); - const bomOffset = startsWithBom(originalText) ? 1 : 0; - const text = originalText.slice(bomOffset); - - const shebangEnd = getShebangEndIndex(text); - const afterShebang = text.slice(shebangEnd); - const leadingWhitespaceLength = - getLeadingWhitespaceLength(afterShebang); - const checkStart = shebangEnd + leadingWhitespaceLength; - - if (hasLicenseHeaderAtStart(text.slice(checkStart))) { - return; - } - - context.report({ - node, - loc: { line: 1, column: 0 }, - messageId: "missing", - fix(fixer) { - const year = context.options?.[0]?.year ?? new Date().getFullYear(); - const headerBlock = renderHeader(year); - - const replacement = - shebangEnd > 0 ? `\n${headerBlock}\n\n` : `${headerBlock}\n\n`; - - const replaceStart = bomOffset + shebangEnd; - const replaceEnd = replaceStart + leadingWhitespaceLength; - return fixer.replaceTextRange( - [replaceStart, replaceEnd], - replacement, - ); - }, - }); - }, - }; - }, -}; - -export default { - meta: { - name: "alloy", - version: "local", - }, - rules: { - "license-header": licenseHeaderRule, - }, -}; From e880a5f9e0727cca9171d7453150394fac66d31a Mon Sep 17 00:00:00 2001 From: Carter McBride <18412686+carterworks@users.noreply.github.com> Date: Fri, 12 Dec 2025 10:45:48 -0700 Subject: [PATCH 05/56] Make rule instead of plugin --- eslint.config.js | 22 +++----- ...{eslintLicensePlugin.js => licenseRule.js} | 52 +++++++++++++------ ...aderRule.spec.js => licensePlugin.spec.js} | 4 +- 3 files changed, 45 insertions(+), 33 deletions(-) rename scripts/eslint/{eslintLicensePlugin.js => licenseRule.js} (82%) rename scripts/specs/{licenseHeaderRule.spec.js => licensePlugin.spec.js} (96%) diff --git a/eslint.config.js b/eslint.config.js index 80f8f9180..2a0aa9451 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -1,15 +1,3 @@ -/* -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 pluginJs from "@eslint/js"; import vitest from "@vitest/eslint-plugin"; import compatPlugin from "eslint-plugin-compat"; @@ -20,7 +8,7 @@ import { defineConfig, globalIgnores } from "eslint/config"; import { glob } from "glob"; import globals from "globals"; // eslint-disable-next-line import/extensions -import licensePlugin from "./scripts/eslint/eslintLicensePlugin.js"; +import license from "./scripts/eslint/licenseRule.js"; const allComponentPaths = glob.sync("packages/core/src/components/*/"); @@ -50,10 +38,14 @@ export default defineConfig([ "**/*AppMeasurement*", ], plugins: { - alloy: licensePlugin, + local: { + rules: { + license, + }, + }, }, rules: { - "alloy/license-header": "error", + "local/license": "error", }, }, { diff --git a/scripts/eslint/eslintLicensePlugin.js b/scripts/eslint/licenseRule.js similarity index 82% rename from scripts/eslint/eslintLicensePlugin.js rename to scripts/eslint/licenseRule.js index 00db55402..80da0a726 100644 --- a/scripts/eslint/eslintLicensePlugin.js +++ b/scripts/eslint/licenseRule.js @@ -25,20 +25,28 @@ const REQUIRED_SUBSTRINGS = [ const dirname = path.dirname(fileURLToPath(import.meta.url)); const LICENSE_BANNER_PATH = path.resolve(dirname, "../../LICENSE_BANNER"); +/** @type {string | undefined} */ let licenseBannerBodyCache; +/** + * Returns the body of the license banner. + * @returns {string} + */ const getLicenseBannerBody = () => { if (licenseBannerBodyCache) { return licenseBannerBodyCache; } - - // LICENSE_BANNER is used for bundles, so we reuse it as the single source of truth - // for the license text and keep only the *year* file-specific. const bannerText = fs.readFileSync(LICENSE_BANNER_PATH, "utf-8").trimEnd(); const lines = bannerText.split(/\r?\n/); + // remove the first line (Copyright 2019 Adobe. All rights reserved.) licenseBannerBodyCache = lines.slice(1).join("\n"); return licenseBannerBodyCache; }; +/** + * Renders the header for the license banner. + * @param {number} year + * @returns {string} + */ const renderHeader = (year) => { return `/* Copyright ${String(year)} Adobe. All rights reserved. @@ -46,8 +54,18 @@ ${getLicenseBannerBody()} */`.trimEnd(); }; +/** + * Checks if the text starts with a byte order mark (BOM) character. + * @param {string} text + * @returns {boolean} + */ const startsWithBom = (text) => text.startsWith("\uFEFF"); +/** + * Returns the index of the end of the shebang line. + * @param {string} text + * @returns {number} + */ const getShebangEndIndex = (text) => { if (!text.startsWith("#!")) { return 0; @@ -56,11 +74,21 @@ const getShebangEndIndex = (text) => { return newlineIndex === -1 ? text.length : newlineIndex + 1; }; +/** + * Returns the length of the leading whitespace in the text. + * @param {string} text + * @returns {number} + */ const getLeadingWhitespaceLength = (text) => { const match = text.match(/^[\t \r\n]*/); return match ? match[0].length : 0; }; +/** + * Checks if the text has a license header at the start. + * @param {string} text + * @returns {boolean} + */ const hasLicenseHeaderAtStart = (text) => { if (!text.startsWith("/*")) { return false; @@ -76,7 +104,11 @@ const hasLicenseHeaderAtStart = (text) => { return REQUIRED_SUBSTRINGS.every((s) => comment.includes(s)); }; -const licenseHeaderRule = { +/** + * The rule for the license header. + * @type {import("eslint").Rule.RuleModule} + */ +export default { meta: { type: "layout", docs: { @@ -100,7 +132,7 @@ const licenseHeaderRule = { }, }, create(context) { - const sourceCode = context.getSourceCode(); + const sourceCode = context.sourceCode; return { Program(node) { @@ -141,13 +173,3 @@ const licenseHeaderRule = { }; }, }; - -export default { - meta: { - name: "alloy", - version: "local", - }, - rules: { - "license-header": licenseHeaderRule, - }, -}; diff --git a/scripts/specs/licenseHeaderRule.spec.js b/scripts/specs/licensePlugin.spec.js similarity index 96% rename from scripts/specs/licenseHeaderRule.spec.js rename to scripts/specs/licensePlugin.spec.js index 54acd863d..d985250f3 100644 --- a/scripts/specs/licenseHeaderRule.spec.js +++ b/scripts/specs/licensePlugin.spec.js @@ -21,7 +21,7 @@ import { describe, it, } from "vitest"; -import alloyPlugin from "../eslint/eslintLicensePlugin.js"; +import rule from "../eslint/licenseRule.js"; RuleTester.afterAll = afterAll; RuleTester.afterEach = afterEach; @@ -37,8 +37,6 @@ const ruleTester = new RuleTester({ }, }); -const rule = alloyPlugin.rules["license-header"]; - const LICENSE_BANNER_PATH = path.resolve(process.cwd(), "LICENSE_BANNER"); const getLicenseBannerBody = () => { const bannerText = fs.readFileSync(LICENSE_BANNER_PATH, "utf-8").trimEnd(); From 81233f8dae740e2c8dc248d7164ebb02e145b54b Mon Sep 17 00:00:00 2001 From: Carter McBride <18412686+carterworks@users.noreply.github.com> Date: Fri, 12 Dec 2025 10:48:48 -0700 Subject: [PATCH 06/56] Run the plugin --- eslint.config.js | 12 ++++++++++++ packages/core/src/components/Consent/types.js | 12 ++++++++++++ .../src/components/EventMerge/createEventMergeId.js | 12 ++++++++++++ .../core/src/components/PushNotifications/types.js | 12 ++++++++++++ packages/core/src/components/RulesEngine/types.js | 12 ++++++++++++ packages/core/src/core/consent/types.js | 12 ++++++++++++ packages/core/src/core/edgeNetwork/types.js | 12 ++++++++++++ packages/core/src/core/identity/types.js | 12 ++++++++++++ packages/core/src/core/types.js | 12 ++++++++++++ packages/core/src/utils/request/types.js | 12 ++++++++++++ packages/core/src/utils/types.js | 12 ++++++++++++ 11 files changed, 132 insertions(+) diff --git a/eslint.config.js b/eslint.config.js index 2a0aa9451..cf98e5c42 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -1,3 +1,15 @@ +/* +Copyright 2025 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 pluginJs from "@eslint/js"; import vitest from "@vitest/eslint-plugin"; import compatPlugin from "eslint-plugin-compat"; diff --git a/packages/core/src/components/Consent/types.js b/packages/core/src/components/Consent/types.js index 6e503f7b6..b64f95da3 100644 --- a/packages/core/src/components/Consent/types.js +++ b/packages/core/src/components/Consent/types.js @@ -1,3 +1,15 @@ +/* +Copyright 2025 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. +*/ + /** * Request payload object with methods for merging different types of data. * diff --git a/packages/core/src/components/EventMerge/createEventMergeId.js b/packages/core/src/components/EventMerge/createEventMergeId.js index f45a3b3e0..ad1bc85f9 100644 --- a/packages/core/src/components/EventMerge/createEventMergeId.js +++ b/packages/core/src/components/EventMerge/createEventMergeId.js @@ -1,3 +1,15 @@ +/* +Copyright 2025 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. +*/ + /* Copyright 20219 Adobe. All rights reserved. This file is licensed to you under the Apache License, Version 2.0 (the "License"); diff --git a/packages/core/src/components/PushNotifications/types.js b/packages/core/src/components/PushNotifications/types.js index 8ed082310..41f0e16f9 100644 --- a/packages/core/src/components/PushNotifications/types.js +++ b/packages/core/src/components/PushNotifications/types.js @@ -1,3 +1,15 @@ +/* +Copyright 2025 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 { Identity } from '../../utils/request/types.js' */ /** diff --git a/packages/core/src/components/RulesEngine/types.js b/packages/core/src/components/RulesEngine/types.js index d562ee8af..64d39a5b4 100644 --- a/packages/core/src/components/RulesEngine/types.js +++ b/packages/core/src/components/RulesEngine/types.js @@ -1,3 +1,15 @@ +/* +Copyright 2025 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. +*/ + /** * @typedef {Record} EventRegistry */ diff --git a/packages/core/src/core/consent/types.js b/packages/core/src/core/consent/types.js index 09e5b0d99..8367a57b7 100644 --- a/packages/core/src/core/consent/types.js +++ b/packages/core/src/core/consent/types.js @@ -1,3 +1,15 @@ +/* +Copyright 2025 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. +*/ + /** * @typedef {Object} ConsentStateMachine * @property {function(string): void} in diff --git a/packages/core/src/core/edgeNetwork/types.js b/packages/core/src/core/edgeNetwork/types.js index bf7205215..d5d7e372c 100644 --- a/packages/core/src/core/edgeNetwork/types.js +++ b/packages/core/src/core/edgeNetwork/types.js @@ -1,3 +1,15 @@ +/* +Copyright 2025 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 { Request } from '../../utils/request/types.js' */ /** diff --git a/packages/core/src/core/identity/types.js b/packages/core/src/core/identity/types.js index b8153c407..10bc33da7 100644 --- a/packages/core/src/core/identity/types.js +++ b/packages/core/src/core/identity/types.js @@ -1,3 +1,15 @@ +/* +Copyright 2025 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 { Logger } from '../../core/types.js' */ /** @import { CookieJar } from '../../utils/types.js' */ diff --git a/packages/core/src/core/types.js b/packages/core/src/core/types.js index fa591d5ba..6a1e24081 100644 --- a/packages/core/src/core/types.js +++ b/packages/core/src/core/types.js @@ -1,3 +1,15 @@ +/* +Copyright 2025 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. +*/ + /** * @typedef {object} AlloyMonitor * @property {function(any): void} [onBeforeLog] diff --git a/packages/core/src/utils/request/types.js b/packages/core/src/utils/request/types.js index 8b55e2332..d7c3d1890 100644 --- a/packages/core/src/utils/request/types.js +++ b/packages/core/src/utils/request/types.js @@ -1,3 +1,15 @@ +/* +Copyright 2025 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. +*/ + /** * Request object with methods to access and modify request properties. * diff --git a/packages/core/src/utils/types.js b/packages/core/src/utils/types.js index faddf19c2..f2f2e5d17 100644 --- a/packages/core/src/utils/types.js +++ b/packages/core/src/utils/types.js @@ -1,3 +1,15 @@ +/* +Copyright 2025 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. +*/ + /** * @typedef {Object} Storage * @property {function(string): string|null} getItem From 77eb6708094e67e0ffa15d386b763bca20b019e1 Mon Sep 17 00:00:00 2001 From: Carter McBride <18412686+carterworks@users.noreply.github.com> Date: Fri, 12 Dec 2025 10:53:57 -0700 Subject: [PATCH 07/56] Fix files with typos in license header --- .../src/components/EventMerge/createEventMergeId.js | 12 ------------ .../core/src/components/Personalization/index.js | 2 +- 2 files changed, 1 insertion(+), 13 deletions(-) diff --git a/packages/core/src/components/EventMerge/createEventMergeId.js b/packages/core/src/components/EventMerge/createEventMergeId.js index ad1bc85f9..7512dc03e 100644 --- a/packages/core/src/components/EventMerge/createEventMergeId.js +++ b/packages/core/src/components/EventMerge/createEventMergeId.js @@ -10,18 +10,6 @@ OF ANY KIND, either express or implied. See the License for the specific languag governing permissions and limitations under the License. */ -/* -Copyright 20219 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 { uuid } from "../../utils/index.js"; export default () => { diff --git a/packages/core/src/components/Personalization/index.js b/packages/core/src/components/Personalization/index.js index a8d95d50b..54d2d542e 100644 --- a/packages/core/src/components/Personalization/index.js +++ b/packages/core/src/components/Personalization/index.js @@ -1,5 +1,5 @@ /* -Copyright 2019 Adobe. Ackll rights reserved. +Copyright 2025 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 From 48216069f5ec9e2ca3ce9b315008612d75de1274 Mon Sep 17 00:00:00 2001 From: Carter McBride <18412686+carterworks@users.noreply.github.com> Date: Fri, 12 Dec 2025 14:18:44 -0700 Subject: [PATCH 08/56] Fix a case where there is no new line after shebang --- scripts/eslint/licenseRule.js | 17 +++++++++++++++-- scripts/specs/licensePlugin.spec.js | 6 ++++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/scripts/eslint/licenseRule.js b/scripts/eslint/licenseRule.js index 80da0a726..b42702a5d 100644 --- a/scripts/eslint/licenseRule.js +++ b/scripts/eslint/licenseRule.js @@ -158,8 +158,21 @@ export default { const year = context.options?.[0]?.year ?? new Date().getFullYear(); const headerBlock = renderHeader(year); - const replacement = - shebangEnd > 0 ? `\n${headerBlock}\n\n` : `${headerBlock}\n\n`; + const replacementPrefix = (() => { + if (shebangEnd === 0) { + return ""; + } + // `shebangEnd` is the index immediately after the shebang line. When the file has a + // trailing `\n` for the shebang line, that character is included, so we only need one + // additional newline to create a blank line before the license header. + // + // If the file has a shebang but no trailing newline, we need to insert two newlines: + // one to end the shebang line and another to create the blank line separation. + const shebangHasTrailingNewline = text[shebangEnd - 1] === "\n"; + return shebangHasTrailingNewline ? "\n" : "\n\n"; + })(); + + const replacement = `${replacementPrefix}${headerBlock}\n\n`; const replaceStart = bomOffset + shebangEnd; const replaceEnd = replaceStart + leadingWhitespaceLength; diff --git a/scripts/specs/licensePlugin.spec.js b/scripts/specs/licensePlugin.spec.js index d985250f3..887afb589 100644 --- a/scripts/specs/licensePlugin.spec.js +++ b/scripts/specs/licensePlugin.spec.js @@ -94,5 +94,11 @@ governing permissions and limitations under the License. errors: [{ messageId: "missing" }], output: `#!/usr/bin/env node\n\n${HEADER_2000}\n\nconsole.log("hi");`, }, + { + code: `#!/usr/bin/env node`, + options: [{ year: 2000 }], + errors: [{ messageId: "missing" }], + output: `#!/usr/bin/env node\n\n${HEADER_2000}\n\n`, + }, ], }); From 43512f14193039049743b9acda4aefb4e1d381ff Mon Sep 17 00:00:00 2001 From: Carter McBride <18412686+carterworks@users.noreply.github.com> Date: Mon, 15 Dec 2025 09:37:31 -0700 Subject: [PATCH 09/56] Integrate changesets --- .changeset/config.json | 13 + .changeset/pre.json | 10 + .github/PULL_REQUEST_TEMPLATE.md | 1 + .github/workflows/changeset-publish.yml | 219 ++++++++++ .github/workflows/deployRelease.yml | 94 ----- .github/workflows/initializeRelease.yml | 18 - .github/workflows/publish-to-npm.yaml | 22 - .github/workflows/triggerRelease.yml | 21 - CONTRIBUTING.md | 27 ++ package.json | 1 + pnpm-lock.yaml | 463 +++++++++++++++++++++ pnpm-workspace.yaml | 1 + scripts/deploy.js | 68 --- scripts/helpers/applicationError.js | 19 - scripts/helpers/createLogger.js | 37 -- scripts/helpers/exec.js | 77 ---- scripts/helpers/publishTag.js | 25 -- scripts/helpers/publishToNpm.js | 30 -- scripts/helpers/publishVersionBranch.js | 32 -- scripts/helpers/setupDeployment.js | 38 -- scripts/helpers/updatePackageVersion.js | 38 -- scripts/helpers/uploadToCDN.js | 50 --- scripts/helpers/withErrorHandling.js | 30 -- scripts/specs/applicationError.spec.js | 32 -- scripts/specs/createLogger.spec.js | 61 --- scripts/specs/exec.spec.js | 69 --- scripts/specs/publishTag.spec.js | 53 --- scripts/specs/publishToNpm.spec.js | 58 --- scripts/specs/publishVersionBranch.spec.js | 65 --- scripts/specs/setupDeployment.spec.js | 54 --- scripts/specs/updatePackageVersion.spec.js | 49 --- scripts/specs/uploadToCDN.spec.js | 62 --- scripts/specs/withErrorHandling.spec.js | 62 --- scripts/uploadToCDN.js | 61 +++ 34 files changed, 796 insertions(+), 1164 deletions(-) create mode 100644 .changeset/config.json create mode 100644 .changeset/pre.json create mode 100644 .github/workflows/changeset-publish.yml delete mode 100644 .github/workflows/deployRelease.yml delete mode 100644 .github/workflows/initializeRelease.yml delete mode 100644 .github/workflows/publish-to-npm.yaml delete mode 100644 .github/workflows/triggerRelease.yml delete mode 100755 scripts/deploy.js delete mode 100644 scripts/helpers/applicationError.js delete mode 100644 scripts/helpers/createLogger.js delete mode 100644 scripts/helpers/exec.js delete mode 100644 scripts/helpers/publishTag.js delete mode 100644 scripts/helpers/publishToNpm.js delete mode 100644 scripts/helpers/publishVersionBranch.js delete mode 100644 scripts/helpers/setupDeployment.js delete mode 100644 scripts/helpers/updatePackageVersion.js delete mode 100644 scripts/helpers/uploadToCDN.js delete mode 100644 scripts/helpers/withErrorHandling.js delete mode 100644 scripts/specs/applicationError.spec.js delete mode 100644 scripts/specs/createLogger.spec.js delete mode 100644 scripts/specs/exec.spec.js delete mode 100644 scripts/specs/publishTag.spec.js delete mode 100644 scripts/specs/publishToNpm.spec.js delete mode 100644 scripts/specs/publishVersionBranch.spec.js delete mode 100644 scripts/specs/setupDeployment.spec.js delete mode 100644 scripts/specs/updatePackageVersion.spec.js delete mode 100644 scripts/specs/uploadToCDN.spec.js delete mode 100644 scripts/specs/withErrorHandling.spec.js create mode 100755 scripts/uploadToCDN.js diff --git a/.changeset/config.json b/.changeset/config.json new file mode 100644 index 000000000..fa13edffb --- /dev/null +++ b/.changeset/config.json @@ -0,0 +1,13 @@ +{ + "$schema": "https://unpkg.com/@changesets/config@3.1.2/schema.json", + "changelog": "@changesets/cli/changelog", + "commit": false, + "fixed": [], + "linked": [], + "access": "public", + "baseBranch": "main", + "updateInternalDependencies": "minor", + "bumpVersionsWithWorkspaceProtocolOnly": true, + "ignore": [] +} + diff --git a/.changeset/pre.json b/.changeset/pre.json new file mode 100644 index 000000000..ff5798e7f --- /dev/null +++ b/.changeset/pre.json @@ -0,0 +1,10 @@ +{ + "mode": "pre", + "tag": "beta", + "initialVersions": { + "@adobe/alloy": "2.30.1-beta.15", + "@adobe/alloy-core": "2.29.0-beta.1", + "@adobe/alloy-sandbox-browser": "0.1.0" + }, + "changesets": [] +} diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 698939379..811dca939 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -31,3 +31,4 @@ - [ ] I have signed the [Adobe Open Source CLA](https://opensource.adobe.com/cla.html) or I'm an Adobe employee. - [ ] I have made any necessary test changes and all tests pass. - [ ] I have run the Sandbox successfully. +- [ ] I have added a Changeset (`pnpm changeset`) or it is not necessary because this PR is not consumer-facing. diff --git a/.github/workflows/changeset-publish.yml b/.github/workflows/changeset-publish.yml new file mode 100644 index 000000000..a162f6eec --- /dev/null +++ b/.github/workflows/changeset-publish.yml @@ -0,0 +1,219 @@ +name: Changeset Publish + +on: + push: + branches: + - main + workflow_dispatch: + +concurrency: changeset-publish-${{ github.ref }} + +jobs: + analyze: + # Avoid re-running when the bot pushes the version bump commit. + if: github.actor != 'github-actions[bot]' + runs-on: ubuntu-latest + outputs: + has_releases: ${{ steps.release_plan.outputs.has_releases }} + is_prerelease: ${{ steps.pre.outputs.is_prerelease }} + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Determine prerelease mode + id: pre + run: | + if [ -f .changeset/pre.json ]; then + MODE=$(node -p "require('./.changeset/pre.json').mode") + else + MODE="none" + fi + + if [ "${MODE}" = "pre" ]; then + echo "is_prerelease=true" >> "${GITHUB_OUTPUT}" + else + echo "is_prerelease=false" >> "${GITHUB_OUTPUT}" + fi + + - name: Setup Node.js + uses: actions/setup-node@v5 + with: + node-version-file: .nvmrc + registry-url: https://registry.npmjs.org + + - name: Setup pnpm + uses: pnpm/action-setup@v4 + with: + version: 10 + + - name: Compute release plan + id: release_plan + run: | + shopt -s nullglob + FILES=(.changeset/*.md) + + if [ ${#FILES[@]} -eq 0 ]; then + echo "has_releases=false" >> "${GITHUB_OUTPUT}" + exit 0 + fi + + # `changeset status` writes JSON to the provided filename, relative to cwd. + pnpm dlx @changesets/cli status --output=changeset-status.json + HAS_RELEASES=$(node -e "const s=require('./changeset-status.json');console.log((s.releases || []).length > 0 ? 'true' : 'false');") + echo "has_releases=${HAS_RELEASES}" >> "${GITHUB_OUTPUT}" + + - name: No release changesets, skipping publish + if: steps.release_plan.outputs.has_releases != 'true' + run: echo "No pending changesets; skipping publish." + + publish_prerelease: + needs: analyze + if: needs.analyze.outputs.has_releases == 'true' && needs.analyze.outputs.is_prerelease == 'true' + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Setup pnpm + uses: pnpm/action-setup@v4 + with: + version: 10 + + - name: Setup Node.js + uses: actions/setup-node@v5 + with: + node-version-file: .nvmrc + cache: pnpm + registry-url: https://registry.npmjs.org + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Version packages + run: pnpm changeset version + + - name: Update lockfile + run: pnpm install --no-frozen-lockfile --ignore-scripts + + - name: Build packages (prepack) + run: pnpm run build + + - name: Commit version changes + run: | + if [ -n "$(git status --porcelain)" ]; then + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git add -A + git commit -m "chore: publish [skip ci]" + fi + + - name: Publish packages + env: + NODE_AUTH_TOKEN: ${{ secrets.ADOBE_BOT_NPM_TOKEN }} + NPM_TOKEN: ${{ secrets.ADOBE_BOT_NPM_TOKEN }} + run: pnpm changeset publish --tag next + + - name: Start ssh-agent for CDN + uses: webfactory/ssh-agent@v0.9.1 + with: + ssh-private-key: | + ${{ secrets.CDN_PRIVATE_KEY }} + + - name: Upload browser artifacts to CDN + run: node scripts/uploadToCDN.js + + - name: Commit and push new version number and tag + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + if [ -n "$(git status --porcelain)" ]; then + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git add -A + git commit -m "chore: re-enter prerelease mode [skip ci]" + fi + git push --follow-tags + + publish_release: + needs: analyze + if: needs.analyze.outputs.has_releases == 'true' && needs.analyze.outputs.is_prerelease != 'true' + runs-on: ubuntu-latest + # Stable releases require a manual approval. + environment: Production + permissions: + contents: write + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Setup pnpm + uses: pnpm/action-setup@v4 + with: + version: 10 + + - name: Setup Node.js + uses: actions/setup-node@v5 + with: + node-version-file: .nvmrc + cache: pnpm + registry-url: https://registry.npmjs.org + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Version packages + run: pnpm changeset version + + - name: Update lockfile + run: pnpm install --no-frozen-lockfile --ignore-scripts + + - name: Build packages (prepack) + run: pnpm run build + + - name: Commit version changes + run: | + if [ -n "$(git status --porcelain)" ]; then + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git add -A + git commit -m "chore: publish [skip ci]" + fi + + - name: Publish packages + env: + NODE_AUTH_TOKEN: ${{ secrets.ADOBE_BOT_NPM_TOKEN }} + NPM_TOKEN: ${{ secrets.ADOBE_BOT_NPM_TOKEN }} + run: pnpm changeset publish + + - name: Start ssh-agent for CDN + uses: webfactory/ssh-agent@v0.9.1 + with: + ssh-private-key: | + ${{ secrets.CDN_PRIVATE_KEY }} + + - name: Upload browser artifacts to CDN + run: node scripts/uploadToCDN.js + + - name: Re-enter beta prerelease for next cycle after a stable release + if: hashFiles('.changeset/pre.json') == '' + run: pnpm changeset pre enter beta + + - name: Commit and push new version number and tag + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + if [ -n "$(git status --porcelain)" ]; then + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git add -A + git commit -m "chore: re-enter prerelease mode [skip ci]" + fi + git push --follow-tags diff --git a/.github/workflows/deployRelease.yml b/.github/workflows/deployRelease.yml deleted file mode 100644 index 883872eb4..000000000 --- a/.github/workflows/deployRelease.yml +++ /dev/null @@ -1,94 +0,0 @@ -name: Deploy Release -on: - workflow_dispatch: - inputs: - version: - description: "Version" - required: true -# Only allow one workflow instance for this branch to run at a time -concurrency: ${{ github.workflow }}-${{ github.ref }} - -# This workflow is split into release and prerelease jobs so that the -# release job can require a manual approval. Otherwise, the release and -# prerelease jobs should be identical. -jobs: - validate: - name: "Validate" - runs-on: ubuntu-latest - steps: - - uses: adobe/project-card-release-automation/validate-version@v2 - with: - token: ${{ secrets.GITHUB_TOKEN }} - version: ${{ github.event.inputs.version }} - release: - name: "Release" - runs-on: ubuntu-latest - needs: validate - # this environment requires manual approval - environment: Production - # final release versions do not contain '-' - if: ${{ contains(github.event.inputs.version, '-') == false }} - steps: - - uses: actions/checkout@v4 - - uses: pnpm/action-setup@v4 - with: - version: 10 - - uses: actions/setup-node@v5 - with: - node-version-file: .nvmrc - - uses: webfactory/ssh-agent@v0.5.3 - with: - ssh-private-key: | - ${{ secrets.ALLOY_BOT_GITHUB_SSH_PRIVATE_KEY }} - ${{ secrets.CDN_PRIVATE_KEY }} - - name: Install dependencies - run: pnpm install --frozen-lockfile - - run: ./scripts/deploy.js ${{ github.event.inputs.version }} latest - env: - NPM_TOKEN: ${{ secrets.ADOBE_BOT_NPM_TOKEN }} - - uses: actions/upload-artifact@v4 - with: - name: build - path: | - ./dist/alloy.js - ./dist/alloy.min.js - prerelease: - name: "Prerelease" - runs-on: ubuntu-latest - needs: validate - # prerelease versions contain '-' - if: ${{ contains(github.event.inputs.version, '-') }} - steps: - - uses: actions/checkout@v4 - - uses: pnpm/action-setup@v4 - with: - version: 10 - - uses: actions/setup-node@v5 - with: - node-version-file: .nvmrc - - uses: webfactory/ssh-agent@v0.9.1 - with: - ssh-private-key: | - ${{ secrets.ALLOY_BOT_GITHUB_SSH_PRIVATE_KEY }} - ${{ secrets.CDN_PRIVATE_KEY }} - - name: Install dependencies - run: pnpm install --frozen-lockfile - - run: ./scripts/deploy.js ${{ github.event.inputs.version }} next - env: - NPM_TOKEN: ${{ secrets.ADOBE_BOT_NPM_TOKEN }} - - uses: actions/upload-artifact@v4 - with: - name: build - path: | - ./dist/alloy.js - ./dist/alloy.min.js - record: - name: "Record Version" - runs-on: ubuntu-latest - needs: [prerelease, release] - if: failure() == false - steps: - - uses: adobe/project-card-release-automation/record-release@v2 - with: - token: ${{ secrets.GITHUB_TOKEN }} - version: ${{ github.event.inputs.version }} diff --git a/.github/workflows/initializeRelease.yml b/.github/workflows/initializeRelease.yml deleted file mode 100644 index f7d6617ee..000000000 --- a/.github/workflows/initializeRelease.yml +++ /dev/null @@ -1,18 +0,0 @@ -name: Initialize Intended Release -on: - workflow_dispatch: - inputs: - type: - description: "Release Type [major|minor|patch]" - required: true - -jobs: - initializeIntendedRelease: - name: "Initialize Intended Release" - runs-on: ubuntu-latest - steps: - - uses: adobe/project-card-release-automation/initialize-card@v2 - with: - token: ${{ secrets.GITHUB_TOKEN }} - releaseType: ${{ github.event.inputs.type }} - projectNumber: 7 diff --git a/.github/workflows/publish-to-npm.yaml b/.github/workflows/publish-to-npm.yaml deleted file mode 100644 index ddc68e524..000000000 --- a/.github/workflows/publish-to-npm.yaml +++ /dev/null @@ -1,22 +0,0 @@ -name: Publish To NPM -on: workflow_dispatch - -jobs: - publish-to-npm: - name: "Publish to NPM" - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: pnpm/action-setup@v4 - with: - version: 10 - - name: Set up Node.js version - uses: actions/setup-node@v5 - with: - node-version-file: .nvmrc - - name: Install dependencies - run: pnpm install --frozen-lockfile - - name: "Publish to NPM" - run: pnpm publish - env: - NODE_AUTH_TOKEN: ${{ secrets.ADOBE_BOT_NPM_TOKEN }} diff --git a/.github/workflows/triggerRelease.yml b/.github/workflows/triggerRelease.yml deleted file mode 100644 index 8ef5ec05c..000000000 --- a/.github/workflows/triggerRelease.yml +++ /dev/null @@ -1,21 +0,0 @@ -name: Trigger Release -on: - project_card: - types: [moved] - push: - branches: - - main - - "v[0-9]+" - - "v[0-9]+.[0-9]+" - workflow_dispatch: - -jobs: - triggerReleaseIfNeeded: - name: "Trigger Release If Needed" - runs-on: ubuntu-latest - steps: - - uses: adobe/project-card-release-automation/trigger-release@v2 - with: - token: ${{ secrets.ALLOY_BOT_GITHUB_TOKEN }} - workflowId: "deployRelease.yml" - projectNumber: 7 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b223eb779..92bea9ace 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -10,6 +10,33 @@ Our guidelines vary depending on the type of contribution: New Feature, Enhancem This project uses `pnpm` as the package manager and targets the latest lts version of Node.js. +## Integration with [Changesets](https://github.com/changesets/changesets) + +This repo uses Changesets to drive **versioning + publishing** for `@adobe/alloy` and `@adobe/alloy-core`. + +### When you need a changeset + +Include a changeset for **consumer-facing** changes (bug fixes, new features, breaking changes, behavioral changes, etc.). + +Skip it for changes that should not result in a publish (docs-only, internal refactors, CI changes, tests-only, etc.). + +### Create a changeset + +1. Run: `pnpm changeset` +2. Select the affected package(s): `@adobe/alloy` and/or `@adobe/alloy-core` +3. Choose the bump (patch/minor/major) and write a short summary +4. Commit the generated `.changeset/*.md` file with your PR + +### What happens on merge + +When changes land on `main`, CI publishes based on the accumulated changesets and uploads browser artifacts to the CDN. + +### Prerelease mode + +To switch from releasing betas to stable releases, or back to betas, use the following commands: +- Beta -> Stable: `pnpm changeset pre exit`, commit, push. +- Stable -> Beta: happens automatically as part of the release process in [.github/workflows/changeset-publish.yml](.github/workflows/changeset-publish.yml). + ## Contributor license agreement All third-party contributions to this project must be accompanied by a signed contributor diff --git a/package.json b/package.json index 1cd8e8ffa..e73826f10 100644 --- a/package.json +++ b/package.json @@ -92,6 +92,7 @@ "@adobe/alloy": "next", "@babel/cli": "^7.28.3", "@babel/plugin-transform-modules-commonjs": "^7.27.1", + "@changesets/cli": "^2.29.8", "@eslint/js": "^9.38.0", "@octokit/rest": "^22.0.1", "@types/node": "^24.9.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2da770cb5..a1393b954 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -63,6 +63,9 @@ importers: '@babel/plugin-transform-modules-commonjs': specifier: ^7.27.1 version: 7.27.1(@babel/core@7.28.5) + '@changesets/cli': + specifier: ^2.29.8 + version: 2.29.8(@types/node@24.9.1) '@eslint/js': specifier: ^9.38.0 version: 9.38.0 @@ -866,6 +869,61 @@ packages: resolution: {integrity: sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==} engines: {node: '>=18'} + '@changesets/apply-release-plan@7.0.14': + resolution: {integrity: sha512-ddBvf9PHdy2YY0OUiEl3TV78mH9sckndJR14QAt87KLEbIov81XO0q0QAmvooBxXlqRRP8I9B7XOzZwQG7JkWA==} + + '@changesets/assemble-release-plan@6.0.9': + resolution: {integrity: sha512-tPgeeqCHIwNo8sypKlS3gOPmsS3wP0zHt67JDuL20P4QcXiw/O4Hl7oXiuLnP9yg+rXLQ2sScdV1Kkzde61iSQ==} + + '@changesets/changelog-git@0.2.1': + resolution: {integrity: sha512-x/xEleCFLH28c3bQeQIyeZf8lFXyDFVn1SgcBiR2Tw/r4IAWlk1fzxCEZ6NxQAjF2Nwtczoen3OA2qR+UawQ8Q==} + + '@changesets/cli@2.29.8': + resolution: {integrity: sha512-1weuGZpP63YWUYjay/E84qqwcnt5yJMM0tep10Up7Q5cS/DGe2IZ0Uj3HNMxGhCINZuR7aO9WBMdKnPit5ZDPA==} + hasBin: true + + '@changesets/config@3.1.2': + resolution: {integrity: sha512-CYiRhA4bWKemdYi/uwImjPxqWNpqGPNbEBdX1BdONALFIDK7MCUj6FPkzD+z9gJcvDFUQJn9aDVf4UG7OT6Kog==} + + '@changesets/errors@0.2.0': + resolution: {integrity: sha512-6BLOQUscTpZeGljvyQXlWOItQyU71kCdGz7Pi8H8zdw6BI0g3m43iL4xKUVPWtG+qrrL9DTjpdn8eYuCQSRpow==} + + '@changesets/get-dependents-graph@2.1.3': + resolution: {integrity: sha512-gphr+v0mv2I3Oxt19VdWRRUxq3sseyUpX9DaHpTUmLj92Y10AGy+XOtV+kbM6L/fDcpx7/ISDFK6T8A/P3lOdQ==} + + '@changesets/get-release-plan@4.0.14': + resolution: {integrity: sha512-yjZMHpUHgl4Xl5gRlolVuxDkm4HgSJqT93Ri1Uz8kGrQb+5iJ8dkXJ20M2j/Y4iV5QzS2c5SeTxVSKX+2eMI0g==} + + '@changesets/get-version-range-type@0.4.0': + resolution: {integrity: sha512-hwawtob9DryoGTpixy1D3ZXbGgJu1Rhr+ySH2PvTLHvkZuQ7sRT4oQwMh0hbqZH1weAooedEjRsbrWcGLCeyVQ==} + + '@changesets/git@3.0.4': + resolution: {integrity: sha512-BXANzRFkX+XcC1q/d27NKvlJ1yf7PSAgi8JG6dt8EfbHFHi4neau7mufcSca5zRhwOL8j9s6EqsxmT+s+/E6Sw==} + + '@changesets/logger@0.1.1': + resolution: {integrity: sha512-OQtR36ZlnuTxKqoW4Sv6x5YIhOmClRd5pWsjZsddYxpWs517R0HkyiefQPIytCVh4ZcC5x9XaG8KTdd5iRQUfg==} + + '@changesets/parse@0.4.2': + resolution: {integrity: sha512-Uo5MC5mfg4OM0jU3up66fmSn6/NE9INK+8/Vn/7sMVcdWg46zfbvvUSjD9EMonVqPi9fbrJH9SXHn48Tr1f2yA==} + + '@changesets/pre@2.0.2': + resolution: {integrity: sha512-HaL/gEyFVvkf9KFg6484wR9s0qjAXlZ8qWPDkTyKF6+zqjBe/I2mygg3MbpZ++hdi0ToqNUF8cjj7fBy0dg8Ug==} + + '@changesets/read@0.6.6': + resolution: {integrity: sha512-P5QaN9hJSQQKJShzzpBT13FzOSPyHbqdoIBUd2DJdgvnECCyO6LmAOWSV+O8se2TaZJVwSXjL+v9yhb+a9JeJg==} + + '@changesets/should-skip-package@0.1.2': + resolution: {integrity: sha512-qAK/WrqWLNCP22UDdBTMPH5f41elVDlsNyat180A33dWxuUDyNpg6fPi/FyTZwRriVjg0L8gnjJn2F9XAoF0qw==} + + '@changesets/types@4.1.0': + resolution: {integrity: sha512-LDQvVDv5Kb50ny2s25Fhm3d9QSZimsoUGBsUioj6MC3qbMUCuC8GPIvk/M6IvXx3lYhAs0lwWUQLb+VIEUCECw==} + + '@changesets/types@6.1.0': + resolution: {integrity: sha512-rKQcJ+o1nKNgeoYRHKOS07tAMNd3YSN0uHaJOZYjBAgxfV7TUE7JE+z4BzZdQwb5hKaYbayKN5KrYV7ODb2rAA==} + + '@changesets/write@0.4.0': + resolution: {integrity: sha512-CdTLvIOPiCNuH71pyDu3rA+Q0n65cmAbXnwWH84rKGiFumFzkmHNT8KHTMEchcxN+Kl8I54xGUhJ7l3E7X396Q==} + '@devexpress/bin-v8-flags-filter@1.3.0': resolution: {integrity: sha512-LWLNfYGwVJKYpmHUDoODltnlqxdEAl5Qmw7ha1+TSpsABeF94NKSWkQTTV1TB4CM02j2pZyqn36nHgaFl8z7qw==} @@ -1295,6 +1353,12 @@ packages: '@jridgewell/trace-mapping@0.3.31': resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + '@manypkg/find-root@1.1.0': + resolution: {integrity: sha512-mki5uBvhHzO8kYYix/WRy2WX8S3B5wdVSc9D6KcU5lQNglP2yt58/VfLuAK49glRXChosY8ap2oJ1qgma3GUVA==} + + '@manypkg/get-packages@1.1.3': + resolution: {integrity: sha512-fo+QhuU3qE/2TQMQmbVMqaQ6EWbMhi4ABWP+O4AM1NqPBuy0OrApV5LO6BrrgnhtAHS2NH6RrVk9OL181tTi8A==} + '@mdn/browser-compat-data@5.7.6': resolution: {integrity: sha512-7xdrMX0Wk7grrTZQwAoy1GkvPMFoizStUoL+VmtUkAxegbCCec+3FKwOM6yc/uGU5+BEczQHXAlWiqvM8JeENg==} @@ -1608,6 +1672,9 @@ packages: resolution: {integrity: sha512-zmPitbQ8+6zNutpwgcQuLcsEpn/Cj54Kbn7L5pX0Os5kdWplB7xPgEh/g+SWOB/qmows2gpuCaPyduq8ZZRnxA==} deprecated: This is a stub types definition. minimatch provides its own type definitions, so you do not need this installed. + '@types/node@12.20.55': + resolution: {integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==} + '@types/node@20.14.5': resolution: {integrity: sha512-aoRR+fJkZT2l0aGOJhuA8frnCSoNX6W7U2mpNq63+BxBIj5BQFt8rHy627kijCmm63ijdSdwvGgpUsU6MBsZZA==} @@ -1764,6 +1831,10 @@ packages: ajv@6.12.6: resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + ansi-colors@4.1.3: + resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} + engines: {node: '>=6'} + ansi-escapes@4.3.2: resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} engines: {node: '>=8'} @@ -1796,6 +1867,9 @@ packages: resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} engines: {node: '>= 8'} + argparse@1.0.10: + resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} + argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} @@ -1919,6 +1993,10 @@ packages: before-after-hook@4.0.0: resolution: {integrity: sha512-q6tR3RPqIB1pMiTRMFcZwuG5T8vwp+vUvEG0vuI6B+Rikh5BfPp2fQ82c925FOs+b0lcFQ8CFrL+KbilfZFhOQ==} + better-path-resolve@1.0.0: + resolution: {integrity: sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g==} + engines: {node: '>=4'} + binary-extensions@2.3.0: resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} engines: {node: '>=8'} @@ -2006,6 +2084,10 @@ packages: ci-info@1.6.0: resolution: {integrity: sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A==} + ci-info@3.9.0: + resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} + engines: {node: '>=8'} + clean-stack@2.2.0: resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==} engines: {node: '>=6'} @@ -2184,6 +2266,10 @@ packages: des.js@1.1.0: resolution: {integrity: sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==} + detect-indent@6.1.0: + resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==} + engines: {node: '>=8'} + device-specs@1.0.1: resolution: {integrity: sha512-rxns/NDZfbdYumnn801z9uo8kWIz3Eld7Bk/F0V9zw4sZemSoD93+gxHEonLdxYulkws4iCMt7ZP8zuM8EzUSg==} @@ -2236,6 +2322,10 @@ packages: end-of-stream@1.4.5: resolution: {integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==} + enquirer@2.4.1: + resolution: {integrity: sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==} + engines: {node: '>=8.6'} + entities@6.0.1: resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==} engines: {node: '>=0.12'} @@ -2394,6 +2484,11 @@ packages: resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + esprima@4.0.1: + resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} + engines: {node: '>=4'} + hasBin: true + esquery@1.6.0: resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} engines: {node: '>=0.10'} @@ -2435,6 +2530,9 @@ packages: resolution: {integrity: sha512-JhFGDVJ7tmDJItKhYgJCGLOWjuK9vPxiXoUFLwLDc99NlmklilbiQJwoctZtt13+xMw91MCk/REan6MWHqDjyA==} engines: {node: '>=12.0.0'} + extendable-error@0.1.7: + resolution: {integrity: sha512-UOiS2in6/Q0FK0R0q6UY9vYpQ21mr/Qn1KOnte7vsACuNJf514WvCCUHSRCPcgjPT2bAhNIJdlE6bVap1GKmeg==} + fast-content-type-parse@3.0.0: resolution: {integrity: sha512-ZvLdcY8P+N8mGQJahJV5G4U88CSvT1rP8ApL6uETe88MBXrBHAkZlSEySdUlyztF7ccb+Znos3TFqaepHxdhBg==} @@ -2481,6 +2579,10 @@ packages: resolution: {integrity: sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==} engines: {node: '>=6'} + find-up@4.1.0: + resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} + engines: {node: '>=8'} + find-up@5.0.0: resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} engines: {node: '>=10'} @@ -2504,6 +2606,14 @@ packages: resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==} engines: {node: '>=12'} + fs-extra@7.0.1: + resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==} + engines: {node: '>=6 <7 || >=8'} + + fs-extra@8.1.0: + resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==} + engines: {node: '>=6 <7 || >=8'} + fs-readdir-recursive@1.1.0: resolution: {integrity: sha512-GNanXlVr2pf02+sPN40XN8HG+ePaNcvM0q5mZBd668Obwb0yD5GiUbZOFgwn8kGMY6I3mdyDJzieUy3PTYyTRA==} @@ -2701,6 +2811,10 @@ packages: resolution: {integrity: sha512-uhSZLPPD2VXXOSN8Cni3kIsoFHaU2pT/nySEU/fHr/ePbqHYr0jeiQRmUKLEirC09SFPsdMoA7LU7UXMd/w0Kw==} engines: {node: '>= 6.15.1'} + human-id@4.1.3: + resolution: {integrity: sha512-tsYlhAYpjCKa//8rXZ9DqKEawhPoSytweBC2eNvcaDK+57RZLHGqNs3PZTQO6yekLFSuvA6AlnAfrw1uBvtb+Q==} + hasBin: true + human-signals@1.1.1: resolution: {integrity: sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==} engines: {node: '>=8.12.0'} @@ -2915,6 +3029,10 @@ packages: resolution: {integrity: sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==} engines: {node: '>= 0.4'} + is-subdir@1.2.0: + resolution: {integrity: sha512-2AT6j+gXe/1ueqbW6fLZJiIw3F8iXGJtt0yDrZaBhAZEG1raiTxKWU+IPqMCzQAXOUCKdA4UDMgacKH25XG2Cw==} + engines: {node: '>=4'} + is-symbol@1.1.1: resolution: {integrity: sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==} engines: {node: '>= 0.4'} @@ -2938,6 +3056,10 @@ packages: resolution: {integrity: sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==} engines: {node: '>= 0.4'} + is-windows@1.0.2: + resolution: {integrity: sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==} + engines: {node: '>=0.10.0'} + isarray@1.0.0: resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} @@ -2990,10 +3112,18 @@ packages: js-tokens@9.0.1: resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==} + js-yaml@3.14.2: + resolution: {integrity: sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==} + hasBin: true + js-yaml@4.1.0: resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} hasBin: true + js-yaml@4.1.1: + resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} + hasBin: true + jsesc@3.0.2: resolution: {integrity: sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==} engines: {node: '>=6'} @@ -3022,6 +3152,9 @@ packages: engines: {node: '>=6'} hasBin: true + jsonfile@4.0.0: + resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} + jsonfile@6.2.0: resolution: {integrity: sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==} @@ -3056,6 +3189,10 @@ packages: resolution: {integrity: sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==} engines: {node: '>=6'} + locate-path@5.0.0: + resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} + engines: {node: '>=8'} + locate-path@6.0.0: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} @@ -3069,6 +3206,9 @@ packages: lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + lodash.startcase@4.4.0: + resolution: {integrity: sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==} + lodash@4.17.21: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} @@ -3199,6 +3339,10 @@ packages: moment@2.30.1: resolution: {integrity: sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==} + mri@1.2.0: + resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} + engines: {node: '>=4'} + mrmime@2.0.1: resolution: {integrity: sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==} engines: {node: '>=10'} @@ -3309,6 +3453,9 @@ packages: resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==} engines: {node: '>=0.10.0'} + outdent@0.5.0: + resolution: {integrity: sha512-/jHxFIzoMXdqPzTaCpFzAAWhpkSjZPF4Vsn6jAfNpmbH/ymsmd7Qc6VE9BGn0L6YMj6uwpQLxCECpus4ukKS9Q==} + outvariant@1.4.3: resolution: {integrity: sha512-+Sl2UErvtsoajRDKCE5/dBz4DIvHXQQnAxtQTF04OJxY0+DyZXSo5P5Bb7XYWOh81syohlYL24hbDwxedPUJCA==} @@ -3316,6 +3463,10 @@ packages: resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==} engines: {node: '>= 0.4'} + p-filter@2.1.0: + resolution: {integrity: sha512-ZBxxZ5sL2HghephhpGAQdoskxplTwr7ICaehZwLIlfL6acuVgZPm8yBNuRAFBGEqtD/hmUeq9eqLg2ys9Xr/yw==} + engines: {node: '>=8'} + p-finally@2.0.1: resolution: {integrity: sha512-vpm09aKwq6H9phqRQzecoDpD8TmVyGw70qmWlyq5onxY7tqyTTFVvxMykxQSQKILBSFlbXpypIw2T1Ml7+DDtw==} engines: {node: '>=8'} @@ -3332,6 +3483,10 @@ packages: resolution: {integrity: sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==} engines: {node: '>=6'} + p-locate@4.1.0: + resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} + engines: {node: '>=8'} + p-locate@5.0.0: resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} engines: {node: '>=10'} @@ -3340,6 +3495,10 @@ packages: resolution: {integrity: sha512-r6zKACMNhjPJMTl8KcFH4li//gkrXWfbD6feV8l6doRHlzljFWGJ2AP6iKaCJXyZmAUMOPtvbW7EXkbWO/pLEA==} engines: {node: '>=4'} + p-map@2.1.0: + resolution: {integrity: sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==} + engines: {node: '>=6'} + p-map@3.0.0: resolution: {integrity: sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==} engines: {node: '>=8'} @@ -3351,6 +3510,9 @@ packages: package-json-from-dist@1.0.1: resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} + package-manager-detector@0.2.11: + resolution: {integrity: sha512-BEnLolu+yuz22S56CU1SUKq3XC3PkwD5wv4ikR4MfGvnRVcmzXR9DwSlW2fEamyTPyXHomBJRzgapeuBvRNzJQ==} + package-name-regex@2.0.6: resolution: {integrity: sha512-gFL35q7kbE/zBaPA3UKhp2vSzcPYx2ecbYuwv1ucE9Il6IIgBDweBlH8D68UFGZic2MkllKa2KHCfC1IQBQUYA==} engines: {node: '>=12'} @@ -3497,6 +3659,11 @@ packages: resolution: {integrity: sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==} engines: {node: '>=6.0.0'} + prettier@2.8.8: + resolution: {integrity: sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==} + engines: {node: '>=10.13.0'} + hasBin: true + prettier@3.6.2: resolution: {integrity: sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==} engines: {node: '>=14'} @@ -3533,6 +3700,9 @@ packages: resolution: {integrity: sha512-ZvWjbAj4MWAj6bnCc9CnculsXnJr7eoKsvH/8rVpZbqYxP2z05HNQa43ZVwe/dVRcFxgfFHE2CkUqn0sCyLfHw==} hasBin: true + quansync@0.2.11: + resolution: {integrity: sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==} + querystringify@2.2.0: resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==} @@ -3587,6 +3757,10 @@ packages: read-file-relative@1.2.0: resolution: {integrity: sha512-lwZUlN2tQyPa62/XmVtX1MeNLVutlRWwqvclWU8YpOCgjKdhg2zyNkeFjy7Rnjo3txhKCy5FGgAi+vx59gvkYg==} + read-yaml-file@1.1.0: + resolution: {integrity: sha512-VIMnQi/Z4HT2Fxuwg5KrY174U1VdUIASQVWXXyqtNRtxSr9IYkn1rsI6Tb6HsrHCmB7gVpNwX6JxPTHcH6IoTA==} + engines: {node: '>=6'} + readable-stream@2.3.8: resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} @@ -3654,6 +3828,10 @@ packages: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} + resolve-from@5.0.0: + resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} + engines: {node: '>=8'} + resolve@1.22.10: resolution: {integrity: sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==} engines: {node: '>= 0.4'} @@ -3843,6 +4021,9 @@ packages: resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} engines: {node: '>=0.10.0'} + spawndamnit@3.0.1: + resolution: {integrity: sha512-MmnduQUuHCoFckZoWnXsTg7JaiLBJrKFj9UI2MbRPGaJeVpsLcVBu6P/IGZovziM/YBsellCmsprgNA+w0CzVg==} + spdx-compare@1.0.0: resolution: {integrity: sha512-C1mDZOX0hnu0ep9dfmuoi03+eOdDoz2yvK79RxbcrVEG1NO1Ph35yW102DHWKN4pk80nwCgeMmSY5L25VE4D9A==} @@ -3864,6 +4045,9 @@ packages: spdx-satisfies@5.0.1: resolution: {integrity: sha512-Nwor6W6gzFp8XX4neaKQ7ChV4wmpSh2sSDemMFSzHxpTw460jxFYeOn+jq4ybnSSw/5sc3pjka9MQPouksQNpw==} + sprintf-js@1.0.3: + resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} + stackback@0.0.2: resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} @@ -3970,6 +4154,10 @@ packages: resolution: {integrity: sha512-MeQTA1r0litLUf0Rp/iisCaL8761lKAZHaimlbGK4j0HysC4PLfqygQj9srcs0m2RdtDYnF8UuYyKpbjHYp7Jw==} engines: {node: ^14.18.0 || >=16.0.0} + term-size@2.2.1: + resolution: {integrity: sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==} + engines: {node: '>=8'} + terser@5.44.0: resolution: {integrity: sha512-nIVck8DK+GM/0Frwd+nIhZ84pR/BX7rmXMfYwyg+Sri5oGVE99/E3KvXqpC2xHFxyqXyGHTKBSioxxplrO4I4w==} engines: {node: '>=10'} @@ -4167,6 +4355,10 @@ packages: universal-user-agent@7.0.3: resolution: {integrity: sha512-TmnEAEAsBJVZM/AADELsK76llnwcf9vMKuPz8JflO1frO8Lchitr0fNaN9d+Ap0BjKtqWqd/J17qeDnXh8CL2A==} + universalify@0.1.2: + resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} + engines: {node: '>= 4.0.0'} + universalify@0.2.0: resolution: {integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==} engines: {node: '>= 4.0.0'} @@ -5270,6 +5462,150 @@ snapshots: '@bcoe/v8-coverage@1.0.2': {} + '@changesets/apply-release-plan@7.0.14': + dependencies: + '@changesets/config': 3.1.2 + '@changesets/get-version-range-type': 0.4.0 + '@changesets/git': 3.0.4 + '@changesets/should-skip-package': 0.1.2 + '@changesets/types': 6.1.0 + '@manypkg/get-packages': 1.1.3 + detect-indent: 6.1.0 + fs-extra: 7.0.1 + lodash.startcase: 4.4.0 + outdent: 0.5.0 + prettier: 2.8.8 + resolve-from: 5.0.0 + semver: 7.7.3 + + '@changesets/assemble-release-plan@6.0.9': + dependencies: + '@changesets/errors': 0.2.0 + '@changesets/get-dependents-graph': 2.1.3 + '@changesets/should-skip-package': 0.1.2 + '@changesets/types': 6.1.0 + '@manypkg/get-packages': 1.1.3 + semver: 7.7.3 + + '@changesets/changelog-git@0.2.1': + dependencies: + '@changesets/types': 6.1.0 + + '@changesets/cli@2.29.8(@types/node@24.9.1)': + dependencies: + '@changesets/apply-release-plan': 7.0.14 + '@changesets/assemble-release-plan': 6.0.9 + '@changesets/changelog-git': 0.2.1 + '@changesets/config': 3.1.2 + '@changesets/errors': 0.2.0 + '@changesets/get-dependents-graph': 2.1.3 + '@changesets/get-release-plan': 4.0.14 + '@changesets/git': 3.0.4 + '@changesets/logger': 0.1.1 + '@changesets/pre': 2.0.2 + '@changesets/read': 0.6.6 + '@changesets/should-skip-package': 0.1.2 + '@changesets/types': 6.1.0 + '@changesets/write': 0.4.0 + '@inquirer/external-editor': 1.0.2(@types/node@24.9.1) + '@manypkg/get-packages': 1.1.3 + ansi-colors: 4.1.3 + ci-info: 3.9.0 + enquirer: 2.4.1 + fs-extra: 7.0.1 + mri: 1.2.0 + p-limit: 2.3.0 + package-manager-detector: 0.2.11 + picocolors: 1.1.1 + resolve-from: 5.0.0 + semver: 7.7.3 + spawndamnit: 3.0.1 + term-size: 2.2.1 + transitivePeerDependencies: + - '@types/node' + + '@changesets/config@3.1.2': + dependencies: + '@changesets/errors': 0.2.0 + '@changesets/get-dependents-graph': 2.1.3 + '@changesets/logger': 0.1.1 + '@changesets/types': 6.1.0 + '@manypkg/get-packages': 1.1.3 + fs-extra: 7.0.1 + micromatch: 4.0.8 + + '@changesets/errors@0.2.0': + dependencies: + extendable-error: 0.1.7 + + '@changesets/get-dependents-graph@2.1.3': + dependencies: + '@changesets/types': 6.1.0 + '@manypkg/get-packages': 1.1.3 + picocolors: 1.1.1 + semver: 7.7.3 + + '@changesets/get-release-plan@4.0.14': + dependencies: + '@changesets/assemble-release-plan': 6.0.9 + '@changesets/config': 3.1.2 + '@changesets/pre': 2.0.2 + '@changesets/read': 0.6.6 + '@changesets/types': 6.1.0 + '@manypkg/get-packages': 1.1.3 + + '@changesets/get-version-range-type@0.4.0': {} + + '@changesets/git@3.0.4': + dependencies: + '@changesets/errors': 0.2.0 + '@manypkg/get-packages': 1.1.3 + is-subdir: 1.2.0 + micromatch: 4.0.8 + spawndamnit: 3.0.1 + + '@changesets/logger@0.1.1': + dependencies: + picocolors: 1.1.1 + + '@changesets/parse@0.4.2': + dependencies: + '@changesets/types': 6.1.0 + js-yaml: 4.1.1 + + '@changesets/pre@2.0.2': + dependencies: + '@changesets/errors': 0.2.0 + '@changesets/types': 6.1.0 + '@manypkg/get-packages': 1.1.3 + fs-extra: 7.0.1 + + '@changesets/read@0.6.6': + dependencies: + '@changesets/git': 3.0.4 + '@changesets/logger': 0.1.1 + '@changesets/parse': 0.4.2 + '@changesets/types': 6.1.0 + fs-extra: 7.0.1 + p-filter: 2.1.0 + picocolors: 1.1.1 + + '@changesets/should-skip-package@0.1.2': + dependencies: + '@changesets/types': 6.1.0 + '@manypkg/get-packages': 1.1.3 + + '@changesets/types@4.1.0': {} + + '@changesets/types@6.1.0': {} + + '@changesets/write@0.4.0': + dependencies: + '@changesets/types': 6.1.0 + fs-extra: 7.0.1 + human-id: 4.1.3 + prettier: 2.8.8 + '@devexpress/bin-v8-flags-filter@1.3.0': {} '@devexpress/callsite-record@4.1.7': @@ -5619,6 +5955,22 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.5 + '@manypkg/find-root@1.1.0': + dependencies: + '@babel/runtime': 7.28.4 + '@types/node': 12.20.55 + find-up: 4.1.0 + fs-extra: 8.1.0 + + '@manypkg/get-packages@1.1.3': + dependencies: + '@babel/runtime': 7.28.4 + '@changesets/types': 4.1.0 + '@manypkg/find-root': 1.1.0 + fs-extra: 8.1.0 + globby: 11.1.0 + read-yaml-file: 1.1.0 + '@mdn/browser-compat-data@5.7.6': {} '@mswjs/interceptors@0.40.0': @@ -5890,6 +6242,8 @@ snapshots: dependencies: minimatch: 10.1.1 + '@types/node@12.20.55': {} + '@types/node@20.14.5': dependencies: undici-types: 5.26.5 @@ -6115,6 +6469,8 @@ snapshots: json-schema-traverse: 0.4.1 uri-js: 4.4.1 + ansi-colors@4.1.3: {} + ansi-escapes@4.3.2: dependencies: type-fest: 0.21.3 @@ -6143,6 +6499,10 @@ snapshots: picomatch: 2.3.1 optional: true + argparse@1.0.10: + dependencies: + sprintf-js: 1.0.3 + argparse@2.0.1: {} array-buffer-byte-length@1.0.2: @@ -6303,6 +6663,10 @@ snapshots: before-after-hook@4.0.0: {} + better-path-resolve@1.0.0: + dependencies: + is-windows: 1.0.2 + binary-extensions@2.3.0: optional: true @@ -6409,6 +6773,8 @@ snapshots: ci-info@1.6.0: {} + ci-info@3.9.0: {} + clean-stack@2.2.0: {} cli-cursor@5.0.0: @@ -6572,6 +6938,8 @@ snapshots: inherits: 2.0.4 minimalistic-assert: 1.0.1 + detect-indent@6.1.0: {} + device-specs@1.0.1: {} devtools-protocol@0.0.1109433: {} @@ -6612,6 +6980,11 @@ snapshots: dependencies: once: 1.4.0 + enquirer@2.4.1: + dependencies: + ansi-colors: 4.1.3 + strip-ansi: 6.0.1 + entities@6.0.1: {} environment@1.1.0: {} @@ -6907,6 +7280,8 @@ snapshots: acorn-jsx: 5.3.2(acorn@8.15.0) eslint-visitor-keys: 4.2.1 + esprima@4.0.1: {} + esquery@1.6.0: dependencies: estraverse: 5.3.0 @@ -6966,6 +7341,8 @@ snapshots: expect-type@1.2.2: {} + extendable-error@0.1.7: {} + fast-content-type-parse@3.0.0: {} fast-deep-equal@3.1.3: {} @@ -7008,6 +7385,11 @@ snapshots: dependencies: locate-path: 3.0.0 + find-up@4.1.0: + dependencies: + locate-path: 5.0.0 + path-exists: 4.0.0 + find-up@5.0.0: dependencies: locate-path: 6.0.0 @@ -7035,6 +7417,18 @@ snapshots: jsonfile: 6.2.0 universalify: 2.0.1 + fs-extra@7.0.1: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 4.0.0 + universalify: 0.1.2 + + fs-extra@8.1.0: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 4.0.0 + universalify: 0.1.2 + fs-readdir-recursive@1.1.0: {} fs.realpath@1.0.0: {} @@ -7255,6 +7649,8 @@ snapshots: httpreq@1.1.1: {} + human-id@4.1.3: {} + human-signals@1.1.1: {} human-signals@2.1.0: {} @@ -7442,6 +7838,10 @@ snapshots: call-bound: 1.0.4 has-tostringtag: 1.0.2 + is-subdir@1.2.0: + dependencies: + better-path-resolve: 1.0.0 + is-symbol@1.1.1: dependencies: call-bound: 1.0.4 @@ -7465,6 +7865,8 @@ snapshots: call-bound: 1.0.4 get-intrinsic: 1.3.0 + is-windows@1.0.2: {} + isarray@1.0.0: {} isarray@2.0.5: {} @@ -7521,10 +7923,19 @@ snapshots: js-tokens@9.0.1: {} + js-yaml@3.14.2: + dependencies: + argparse: 1.0.10 + esprima: 4.0.1 + js-yaml@4.1.0: dependencies: argparse: 2.0.1 + js-yaml@4.1.1: + dependencies: + argparse: 2.0.1 + jsesc@3.0.2: {} jsesc@3.1.0: {} @@ -7541,6 +7952,10 @@ snapshots: json5@2.2.3: {} + jsonfile@4.0.0: + optionalDependencies: + graceful-fs: 4.2.11 + jsonfile@6.2.0: dependencies: universalify: 2.0.1 @@ -7593,6 +8008,10 @@ snapshots: p-locate: 3.0.0 path-exists: 3.0.0 + locate-path@5.0.0: + dependencies: + p-locate: 4.1.0 + locate-path@6.0.0: dependencies: p-locate: 5.0.0 @@ -7603,6 +8022,8 @@ snapshots: lodash.merge@4.6.2: {} + lodash.startcase@4.4.0: {} + lodash@4.17.21: {} log-update-async-hook@2.0.7: @@ -7722,6 +8143,8 @@ snapshots: moment@2.30.1: {} + mri@1.2.0: {} + mrmime@2.0.1: {} ms@2.1.2: {} @@ -7843,6 +8266,8 @@ snapshots: os-tmpdir@1.0.2: {} + outdent@0.5.0: {} + outvariant@1.4.3: {} own-keys@1.0.1: @@ -7851,6 +8276,10 @@ snapshots: object-keys: 1.1.1 safe-push-apply: 1.0.0 + p-filter@2.1.0: + dependencies: + p-map: 2.1.0 + p-finally@2.0.1: {} p-limit@2.3.0: @@ -7865,12 +8294,18 @@ snapshots: dependencies: p-limit: 2.3.0 + p-locate@4.1.0: + dependencies: + p-limit: 2.3.0 + p-locate@5.0.0: dependencies: p-limit: 3.1.0 p-map@1.2.0: {} + p-map@2.1.0: {} + p-map@3.0.0: dependencies: aggregate-error: 3.1.0 @@ -7879,6 +8314,10 @@ snapshots: package-json-from-dist@1.0.1: {} + package-manager-detector@0.2.11: + dependencies: + quansync: 0.2.11 + package-name-regex@2.0.6: {} parent-module@1.0.1: @@ -7983,6 +8422,8 @@ snapshots: dependencies: fast-diff: 1.3.0 + prettier@2.8.8: {} + prettier@3.6.2: {} pretty-hrtime@1.0.3: {} @@ -8017,6 +8458,8 @@ snapshots: qrcode-terminal@0.10.0: {} + quansync@0.2.11: {} + querystringify@2.2.0: {} queue-microtask@1.2.3: {} @@ -8066,6 +8509,13 @@ snapshots: dependencies: callsite: 1.0.0 + read-yaml-file@1.1.0: + dependencies: + graceful-fs: 4.2.11 + js-yaml: 3.14.2 + pify: 4.0.1 + strip-bom: 3.0.0 + readable-stream@2.3.8: dependencies: core-util-is: 1.0.3 @@ -8146,6 +8596,8 @@ snapshots: resolve-from@4.0.0: {} + resolve-from@5.0.0: {} + resolve@1.22.10: dependencies: is-core-module: 2.16.1 @@ -8371,6 +8823,11 @@ snapshots: source-map@0.6.1: {} + spawndamnit@3.0.1: + dependencies: + cross-spawn: 7.0.6 + signal-exit: 4.1.0 + spdx-compare@1.0.0: dependencies: array-find-index: 1.0.2 @@ -8398,6 +8855,8 @@ snapshots: spdx-expression-parse: 3.0.1 spdx-ranges: 2.1.1 + sprintf-js@1.0.3: {} + stackback@0.0.2: {} stackframe@1.3.4: {} @@ -8522,6 +8981,8 @@ snapshots: dependencies: '@pkgr/core': 0.2.9 + term-size@2.2.1: {} + terser@5.44.0: dependencies: '@jridgewell/source-map': 0.3.11 @@ -8870,6 +9331,8 @@ snapshots: universal-user-agent@7.0.3: {} + universalify@0.1.2: {} + universalify@0.2.0: {} universalify@2.0.1: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index b7e98c06b..c93d60590 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -1,4 +1,5 @@ packages: + - . - sandboxes/* - packages/* linkWorkspacePackages: true diff --git a/scripts/deploy.js b/scripts/deploy.js deleted file mode 100755 index e9f751b2c..000000000 --- a/scripts/deploy.js +++ /dev/null @@ -1,68 +0,0 @@ -#!/usr/bin/env node - -/* -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 { createRequire } from "module"; -import { execSync } from "child_process"; -import urlExists from "url-exists-nodejs"; -import createLogger from "./helpers/createLogger.js"; -import exec from "./helpers/exec.js"; -import publishTag from "./helpers/publishTag.js"; -import publishToNpm from "./helpers/publishToNpm.js"; -import publishVersionBranch from "./helpers/publishVersionBranch.js"; -import setupDeployment from "./helpers/setupDeployment.js"; -import updatePackageVersion from "./helpers/updatePackageVersion.js"; -import uploadToCDN from "./helpers/uploadToCDN.js"; -import withErrorHandling from "./helpers/withErrorHandling.js"; - -const require = createRequire(import.meta.url); -const { version: currentVersion } = require("../package.json"); - -const logger = createLogger(console, () => Date.now()); - -const args = process.argv.slice(2); - -if (args.length < 2) { - logger.error("Usage: ./deploy.js version npmTag"); - logger.error("Deploy failed."); - process.exit(1); -} - -const [version, npmTag] = args; - -// dependency injection container -const container = { - currentVersion, - exec, - execSync, - githubActor: process.env.GITHUB_ACTOR, - githubRef: process.env.GITHUB_REF, - githubRepository: process.env.GITHUB_REPOSITORY, - logger, - npmTag, - npmToken: process.env.NPM_TOKEN, - process, - urlExists, - version, -}; - -const run = async () => { - await setupDeployment(container); - await updatePackageVersion(container); - await publishToNpm(container); - await publishTag(container); - await publishVersionBranch(container); - await uploadToCDN(container); -}; - -withErrorHandling(container, `Deploy ${version}`, run); diff --git a/scripts/helpers/applicationError.js b/scripts/helpers/applicationError.js deleted file mode 100644 index 79550fc92..000000000 --- a/scripts/helpers/applicationError.js +++ /dev/null @@ -1,19 +0,0 @@ -/* -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. -*/ -class ApplicationError extends Error { - constructor(message) { - super(message); - this.name = "ApplicationError"; - } -} - -export default ApplicationError; diff --git a/scripts/helpers/createLogger.js b/scripts/helpers/createLogger.js deleted file mode 100644 index 163e2ea33..000000000 --- a/scripts/helpers/createLogger.js +++ /dev/null @@ -1,37 +0,0 @@ -/* -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 chalk from "chalk"; -// eslint-disable-next-line import/extensions -import formatDate from "date-fns/format"; - -const buildLogger = - (logFunc, chalkFunc, dateFactory) => - (firstArg, ...restArgs) => { - let newFirstArg = firstArg; - if (typeof firstArg === "string") { - const date = formatDate(dateFactory(), "HH:mm:ss.SSS"); - const prefix = chalk.white(`[${date}]`); - newFirstArg = `${prefix} ${chalkFunc(firstArg)}`; - } - logFunc(newFirstArg, ...restArgs); - }; - -const createLogger = (console, dateFactory) => { - return { - log: buildLogger(console.log.bind(console), (s) => s, dateFactory), - info: buildLogger(console.info.bind(console), (s) => s, dateFactory), - warn: buildLogger(console.warn.bind(console), chalk.yellow, dateFactory), - error: buildLogger(console.error.bind(console), chalk.red, dateFactory), - }; -}; - -export default createLogger; diff --git a/scripts/helpers/exec.js b/scripts/helpers/exec.js deleted file mode 100644 index 97e4f9591..000000000 --- a/scripts/helpers/exec.js +++ /dev/null @@ -1,77 +0,0 @@ -/* -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 { exec as execChildProcess } from "child_process"; -import ApplicationError from "./applicationError.js"; -import readline from "readline"; - -const timestampFormatter = new Intl.DateTimeFormat("en-GB", { - hour: "2-digit", - minute: "2-digit", - second: "2-digit", - fractionalSecondDigits: 3, - hourCycle: "h23", // Explicitly use 24-hour cycle -}); -const formatTimestamp = (date = new Date()) => { - return timestampFormatter.format(date); -}; - -/** - * Pipes a stream line-by-line with timestamped prefixes. - * @param {NodeJS.ReadableStream} stream - * @param {string} name - * @param {import("stream").Writable} outputStream - */ -const pipeWithPrefix = (stream, name, outputStream) => { - const rl = readline.createInterface({ input: stream }); - rl.on("line", (line) => { - outputStream.write(`[${formatTimestamp()} ${name}] ${line}\n`); - }); -}; - -/** - * Executes a function in a child process, with log prefixing. - * @param {string} name - * @param {string} command - * @param {{ outputStream?: import("stream").Writable }} [options={}] - * @returns {Promise} - */ -const exec = async (name, command, options = {}) => { - /** @type {import("child_process").ChildProcess | null} */ - const { outputStream = process.stdout, ...execOptions } = options; - const child = execChildProcess(command, execOptions); - - pipeWithPrefix(child.stdout, name, outputStream); - pipeWithPrefix(child.stderr, name, outputStream); - - return new Promise((resolve, reject) => { - child.on("close", (code) => { - if (code === 0) { - resolve(); - return; - } - outputStream.write( - `[${formatTimestamp()} ${name}] exited with code ${code}.\n`, - ); - reject( - new ApplicationError(`Command "${command}" exited with code ${code}.`), - ); - }); - child.on("error", (err) => { - outputStream.write( - `[${formatTimestamp()} ${name}] Process error: ${err.message}\n`, - ); - reject(err); - }); - }); -}; - -export default exec; diff --git a/scripts/helpers/publishTag.js b/scripts/helpers/publishTag.js deleted file mode 100644 index 511a998f3..000000000 --- a/scripts/helpers/publishTag.js +++ /dev/null @@ -1,25 +0,0 @@ -/* -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. -*/ -const publishTag = async ({ exec, execSync, logger, version }) => { - const publishedTagData = execSync( - `git ls-remote gh-origin refs/tags/v${version}`, - ).toString(); - if (publishedTagData !== "") { - logger.warn(`Git tag v${version} already published.`); - } else { - logger.info(`Publishing Git tag v${version}.`); - await exec("git tag", `git tag -a "v${version}" -m "${version}"`); - await exec("git push", `git push gh-origin v${version}`); - } -}; - -export default publishTag; diff --git a/scripts/helpers/publishToNpm.js b/scripts/helpers/publishToNpm.js deleted file mode 100644 index e658ae7a9..000000000 --- a/scripts/helpers/publishToNpm.js +++ /dev/null @@ -1,30 +0,0 @@ -/* -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. -*/ -const publishToNpm = async ({ exec, execSync, logger, npmTag, version }) => { - let publishVersionJson = ""; - try { - publishVersionJson = execSync( - `pnpm view @adobe/alloy@${version} version --json`, - ).toString(); - } catch { - // the error is already printed to stdErr - } - if (publishVersionJson !== "") { - logger.warn(`NPM already has version ${version}.`); - } else { - logger.info("Publishing NPM package."); - await exec("npm publish", `npm publish -access public --tag ${npmTag}`); - await exec("sleep 60", "sleep 60"); - } -}; - -export default publishToNpm; diff --git a/scripts/helpers/publishVersionBranch.js b/scripts/helpers/publishVersionBranch.js deleted file mode 100644 index b484a56d5..000000000 --- a/scripts/helpers/publishVersionBranch.js +++ /dev/null @@ -1,32 +0,0 @@ -/* -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 semver from "semver"; - -const publishVersionBranch = async ({ exec, execSync, logger, version }) => { - if (semver.prerelease(version) !== null) { - logger.info("No need to create a test branch for a prerelease version."); - return; - } - - const publishedBranchData = execSync( - `git ls-remote gh-origin refs/heads/v${version}`, - ).toString(); - if (publishedBranchData !== "") { - logger.warn(`Git branch v${version} already published.`); - } else { - logger.info(`Publishing Git branch v${version}.`); - await exec("git branch", `git branch "v${version}"`); - await exec("git push", `git push gh-origin HEAD:refs/heads/v${version}`); - } -}; - -export default publishVersionBranch; diff --git a/scripts/helpers/setupDeployment.js b/scripts/helpers/setupDeployment.js deleted file mode 100644 index ae9408758..000000000 --- a/scripts/helpers/setupDeployment.js +++ /dev/null @@ -1,38 +0,0 @@ -/* -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. -*/ - -const setupDeployment = async ({ - exec, - githubActor, - githubRepository, - logger, - npmToken, -}) => { - logger.info("Configuring git."); - await exec("git config", `git config user.name ${githubActor}`); - await exec( - "git config", - `git config user.email gh-actions-${githubActor}@github.com`, - ); - await exec( - "git remote add", - `git remote add gh-origin git@github.com:${githubRepository}.git`, - ); - logger.info("Configuring NPM."); - await exec( - "npm config", - `npm config set //registry.npmjs.org/:_authToken=${npmToken}`, - ); - logger.info("Configure done"); -}; - -export default setupDeployment; diff --git a/scripts/helpers/updatePackageVersion.js b/scripts/helpers/updatePackageVersion.js deleted file mode 100644 index c538d8e8a..000000000 --- a/scripts/helpers/updatePackageVersion.js +++ /dev/null @@ -1,38 +0,0 @@ -/* -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. -*/ -const updatePackage = async ({ - currentVersion, - exec, - githubRef, - logger, - version, -}) => { - if (currentVersion === version) { - logger.warn(`Version in package.json is already ${version}.`); - } else { - // build to update bundlesize.json - await exec("pnpm run build", "pnpm run build"); - logger.info(`Updating package.json with version ${version}.`); - await exec( - "pnpm version", - `pnpm version ${version} --git-tag-version=false`, - ); - await exec( - "git add", - "git add package.json pnpm-lock.yaml bundlesize.json", - ); - await exec("git commit", `git commit -m "[skip ci] ${version}"`); - await exec("git push", `git push gh-origin HEAD:${githubRef}`); - } -}; - -export default updatePackage; diff --git a/scripts/helpers/uploadToCDN.js b/scripts/helpers/uploadToCDN.js deleted file mode 100644 index 19a174fcf..000000000 --- a/scripts/helpers/uploadToCDN.js +++ /dev/null @@ -1,50 +0,0 @@ -/* -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 ApplicationError from "./applicationError.js"; - -const uploadToCDN = async ({ exec, logger, urlExists, version }) => { - const ensureUrlResolves = async (url) => { - if (!(await urlExists(url))) { - throw new ApplicationError(`File not found on CDN: ${url}`); - } - }; - - // We don't do a check here because there is no harm in re-building and re-uploading the files. - - logger.info("Building files for CDN"); - await exec("build", "pnpm run build"); - - // When sftp commands are run in batch mode (-b flag), commands prefixed with "-" do not fail the - // entire script. By prefixing mkdir with "-", this will not fail if the directory already exists. - const ftpCommands = `-mkdir ${version} -cd ${version} -put ./dist/alloy.js -put ./dist/alloy.min.js -put ./dist/alloyServiceWorker.js -put ./dist/alloyServiceWorker.min.js -bye -`; - logger.info("Uploading files to CDN."); - await exec( - "sftp", - `echo "${ftpCommands}" | sftp -oHostKeyAlgorithms=+ssh-dss -oStrictHostKeyChecking=no -b - sshacs@dxresources.ssh.upload.akamai.com:/prod/alloy`, - ); - - await ensureUrlResolves( - `https://cdn1.adoberesources.net/alloy/${version}/alloy.js`, - ); - await ensureUrlResolves( - `https://cdn1.adoberesources.net/alloy/${version}/alloy.min.js`, - ); -}; - -export default uploadToCDN; diff --git a/scripts/helpers/withErrorHandling.js b/scripts/helpers/withErrorHandling.js deleted file mode 100644 index 38b2555e6..000000000 --- a/scripts/helpers/withErrorHandling.js +++ /dev/null @@ -1,30 +0,0 @@ -/* -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 ApplicationError from "./applicationError.js"; - -const withErrorHandling = async ({ logger, process }, operation, func) => { - try { - logger.info(`${operation}.`); - await func(); - logger.info(`${operation} COMPLETE.`); - } catch (e) { - logger.error(`${operation} FAILED.`); - if (e instanceof ApplicationError) { - logger.error(e.message); - } else { - logger.error("An unexpected error was thrown.", e); - } - process.exit(1); - } -}; - -export default withErrorHandling; diff --git a/scripts/specs/applicationError.spec.js b/scripts/specs/applicationError.spec.js deleted file mode 100644 index da1e80f25..000000000 --- a/scripts/specs/applicationError.spec.js +++ /dev/null @@ -1,32 +0,0 @@ -/* -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 { describe, it, expect } from "vitest"; -import ApplicationError from "../helpers/applicationError.js"; - -describe("ApplicationError", () => { - it("sets the name of the error", () => { - try { - throw new ApplicationError("foo"); - } catch (e) { - expect(e.name).toEqual("ApplicationError"); - } - }); - - it("works with instanceof", () => { - try { - throw new ApplicationError("foo"); - } catch (e) { - expect(e instanceof ApplicationError).toBeTruthy(); - } - }); -}); diff --git a/scripts/specs/createLogger.spec.js b/scripts/specs/createLogger.spec.js deleted file mode 100644 index 9d91d199a..000000000 --- a/scripts/specs/createLogger.spec.js +++ /dev/null @@ -1,61 +0,0 @@ -/* -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 { vi, describe, beforeEach, it, expect } from "vitest"; -import chalk from "chalk"; -import createLogger from "../helpers/createLogger.js"; - -describe("createLogger", () => { - let myConsole; - let logger; - const now = new Date(2001, 2, 3, 4, 5, 6, 7); - const prefix = chalk.white("[04:05:06.007]"); - beforeEach(() => { - myConsole = { log: vi.fn(), warn: vi.fn(), error: vi.fn(), info: vi.fn() }; - logger = createLogger(myConsole, () => now); - }); - - it("adds a prefix", () => { - logger.log("mylog"); - - expect(myConsole.log).toHaveBeenCalledTimes(1); - expect(myConsole.log).toHaveBeenCalledWith(`${prefix} mylog`); - }); - - it("leaves objects alone", () => { - const err = new Error("myerror"); - logger.error(err); - - expect(myConsole.error).toHaveBeenCalledTimes(1); - expect(myConsole.error).toHaveBeenCalledWith(err); - }); - - it("logs warnings yellow", () => { - logger.warn("mywarn"); - expect(myConsole.warn).toHaveBeenCalledTimes(1); - expect(myConsole.warn).toHaveBeenCalledWith( - `${prefix} ${chalk.yellow("mywarn")}`, - ); - }); - it("logs errors red", () => { - logger.error("myerror"); - expect(myConsole.error).toHaveBeenCalledWith( - `${prefix} ${chalk.red("myerror")}`, - ); - }); - it("logs additional parameters", () => { - logger.info("a", "b"); - - expect(myConsole.info).toHaveBeenCalledTimes(1); - expect(myConsole.info).toHaveBeenCalledWith(`${prefix} a`, "b"); - }); -}); diff --git a/scripts/specs/exec.spec.js b/scripts/specs/exec.spec.js deleted file mode 100644 index 824a2abf4..000000000 --- a/scripts/specs/exec.spec.js +++ /dev/null @@ -1,69 +0,0 @@ -/* -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 { describe, it, expect } from "vitest"; -import { Writable } from "stream"; -import exec from "../helpers/exec.js"; -import ApplicationError from "../helpers/applicationError.js"; - -const createStringBackedWritableStream = () => { - let result = ""; - class WritableStream extends Writable { - // eslint-disable-next-line class-methods-use-this - _write(chunk, encoding, next) { - result += chunk.toString(); - next(); - } - } - - return [new WritableStream(), () => result]; -}; - -describe("exec", () => { - it("throws an ApplicationError on a non-zero exit code.", async () => { - const [outputStream] = createStringBackedWritableStream(); - await expect(exec("bad exit", "exit 42", { outputStream })).rejects.toThrow( - ApplicationError, - ); - }); - - it("logs the exit code", async () => { - const [outputStream, getResult] = createStringBackedWritableStream(); - try { - await exec("bad exit", "exit 42", { outputStream }); - throw new Error("Test failed"); - } catch { - const result = getResult(); - expect(result).toMatch(/exited with code 42/); - } - }); - - it("logs the process name", async () => { - const [outputStream, getResult] = createStringBackedWritableStream(); - try { - await exec("bad exit", "exit 42", { outputStream }); - throw new Error("Test failed"); - } catch { - const result = getResult(); - expect(result).toMatch(/bad exit/); - } - }); - - it("handles multi-line echo statements", async () => { - const [outputStream, getResult] = createStringBackedWritableStream(); - const input = "Hello\nWorld\n"; - await exec("passthrough", `echo "${input}" | cat -`, { outputStream }); - const result = getResult(); - expect(result).toMatch(/Hello/); - expect(result).toMatch(/World/); - }); -}); diff --git a/scripts/specs/publishTag.spec.js b/scripts/specs/publishTag.spec.js deleted file mode 100644 index fd2cb97f5..000000000 --- a/scripts/specs/publishTag.spec.js +++ /dev/null @@ -1,53 +0,0 @@ -/* -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 { vi, describe, beforeEach, it, expect } from "vitest"; -import publishTag from "../helpers/publishTag.js"; - -describe("publishTag", () => { - let exec; - let execSync; - let logger; - let container; - - beforeEach(() => { - exec = vi.fn(); - execSync = vi.fn(); - logger = { warn: vi.fn(), info: vi.fn() }; - container = { exec, execSync, logger, version: "1.2.3" }; - }); - - it("doesn't publish a tag", async () => { - execSync.mockReturnValue("v1.2.3"); - await publishTag(container); - - expect(logger.warn).toHaveBeenCalledTimes(1); - expect(logger.warn).toHaveBeenCalledWith( - "Git tag v1.2.3 already published.", - ); - expect(logger.info).not.toHaveBeenCalled(); - expect(exec).not.toHaveBeenCalled(); - }); - it("publishes a tag", async () => { - execSync.mockReturnValue(""); - exec - .mockReturnValueOnce(Promise.resolve()) - .mockReturnValueOnce(Promise.resolve()); - await publishTag(container); - - expect(logger.info).toHaveBeenCalledTimes(1); - expect(logger.info).toHaveBeenCalledWith("Publishing Git tag v1.2.3."); - expect(logger.warn).not.toHaveBeenCalled(); - expect(exec).toHaveBeenCalledWith("git tag", expect.any(String)); - expect(exec).toHaveBeenCalledWith("git push", expect.any(String)); - }); -}); diff --git a/scripts/specs/publishToNpm.spec.js b/scripts/specs/publishToNpm.spec.js deleted file mode 100644 index b245be7d3..000000000 --- a/scripts/specs/publishToNpm.spec.js +++ /dev/null @@ -1,58 +0,0 @@ -/* -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 { vi, describe, beforeEach, it, expect } from "vitest"; -import publishToNpm from "../helpers/publishToNpm.js"; - -describe("publishToNpm", () => { - let exec; - let execSync; - let logger; - const npmTag = "mytag"; - const version = "1.2.3"; - let container; - - beforeEach(() => { - exec = vi.fn(); - execSync = vi.fn(); - logger = { warn: vi.fn(), info: vi.fn() }; - container = { exec, execSync, logger, npmTag, version }; - }); - - it("publishes to NPM", async () => { - execSync.mockReturnValue(""); - await publishToNpm(container); - - expect(execSync).toHaveBeenCalledTimes(1); - expect(execSync).toHaveBeenCalledWith( - "pnpm view @adobe/alloy@1.2.3 version --json", - ); - expect(logger.warn).not.toHaveBeenCalled(); - expect(logger.info).toHaveBeenCalledWith("Publishing NPM package."); - expect(exec).toHaveBeenCalledWith("npm publish", expect.any(String)); - }); - - it("doesn't publish to NPM", async () => { - execSync.mockReturnValue('"1.2.3"'); - await publishToNpm(container); - - expect(execSync).toHaveBeenCalledTimes(1); - expect(execSync).toHaveBeenCalledWith( - "pnpm view @adobe/alloy@1.2.3 version --json", - ); - - expect(logger.warn).toHaveBeenCalledTimes(1); - expect(logger.warn).toHaveBeenCalledWith("NPM already has version 1.2.3."); - expect(logger.info).not.toHaveBeenCalled(); - expect(exec).not.toHaveBeenCalled(); - }); -}); diff --git a/scripts/specs/publishVersionBranch.spec.js b/scripts/specs/publishVersionBranch.spec.js deleted file mode 100644 index 987bd7673..000000000 --- a/scripts/specs/publishVersionBranch.spec.js +++ /dev/null @@ -1,65 +0,0 @@ -/* -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 { vi, describe, beforeEach, it, expect } from "vitest"; -import publishVersionBranch from "../helpers/publishVersionBranch.js"; - -describe("publishVersionBranch", () => { - let exec; - let execSync; - let logger; - let container; - - beforeEach(() => { - exec = vi.fn(); - execSync = vi.fn(); - logger = { warn: vi.fn(), info: vi.fn() }; - container = { exec, execSync, logger, version: "1.2.3" }; - }); - - it("doesn't publish a prerelease branch", async () => { - container.version = "1.2.3-beta.0"; - await publishVersionBranch(container); - - expect(logger.info).toHaveBeenCalledTimes(1); - expect(logger.info).toHaveBeenCalledWith( - "No need to create a test branch for a prerelease version.", - ); - expect(logger.warn).not.toHaveBeenCalled(); - expect(execSync).not.toHaveBeenCalled(); - expect(exec).not.toHaveBeenCalled(); - }); - - it("doesn't publish a branch that was already published", async () => { - execSync.mockReturnValue("v1.2.3"); - await publishVersionBranch(container); - - expect(logger.warn).toHaveBeenCalledTimes(1); - expect(logger.warn).toHaveBeenCalledWith( - "Git branch v1.2.3 already published.", - ); - expect(logger.info).not.toHaveBeenCalled(); - expect(exec).not.toHaveBeenCalled(); - }); - - it("publishes a branch", async () => { - execSync.mockReturnValue(""); - exec.mockReturnValue(Promise.resolve(), Promise.resolve()); - await publishVersionBranch(container); - - expect(logger.info).toHaveBeenCalledTimes(1); - expect(logger.info).toHaveBeenCalledWith("Publishing Git branch v1.2.3."); - expect(logger.warn).not.toHaveBeenCalled(); - expect(exec).toHaveBeenCalledWith("git branch", expect.any(String)); - expect(exec).toHaveBeenCalledWith("git push", expect.any(String)); - }); -}); diff --git a/scripts/specs/setupDeployment.spec.js b/scripts/specs/setupDeployment.spec.js deleted file mode 100644 index 5bb66d6df..000000000 --- a/scripts/specs/setupDeployment.spec.js +++ /dev/null @@ -1,54 +0,0 @@ -/* -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 { vi, describe, beforeEach, it, expect } from "vitest"; -import setupDeployment from "../helpers/setupDeployment.js"; - -describe("setupDeployment", () => { - let exec; - const githubActor = "myactor"; - const githubRepository = "myrepo"; - let logger; - const npmToken = "mytoken"; - let container; - - beforeEach(() => { - exec = vi.fn(); - logger = { info: vi.fn() }; - container = { - exec, - githubActor, - githubRepository, - logger, - npmToken, - container, - }; - }); - - it("runs setup", async () => { - await setupDeployment(container); - expect(logger.info).toHaveBeenCalled(); - // make sure all the container parameters are defined - expect(exec).toHaveBeenCalledWith( - expect.anything(), - expect.stringMatching(/myactor/), - ); - expect(exec).toHaveBeenCalledWith( - expect.anything(), - expect.stringMatching(/myrepo/), - ); - expect(exec).toHaveBeenCalledWith( - expect.anything(), - expect.stringMatching(/mytoken/), - ); - }); -}); diff --git a/scripts/specs/updatePackageVersion.spec.js b/scripts/specs/updatePackageVersion.spec.js deleted file mode 100644 index ed7304b08..000000000 --- a/scripts/specs/updatePackageVersion.spec.js +++ /dev/null @@ -1,49 +0,0 @@ -/* -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 { vi, describe, beforeEach, it, expect } from "vitest"; -import updatePackageVersion from "../helpers/updatePackageVersion.js"; - -describe("updatePackageVersion", () => { - let exec; - const githubRef = "mygithubref"; - let logger; - const version = "1.2.3"; - let container; - - beforeEach(() => { - exec = vi.fn().mockReturnValue(Promise.resolve()); - logger = { warn: vi.fn(), info: vi.fn() }; - container = { exec, githubRef, logger, version }; - }); - - it("updates the package version", async () => { - await updatePackageVersion({ currentVersion: "1.2.2", ...container }); - expect(logger.warn).not.toHaveBeenCalled(); - expect(logger.info).toHaveBeenCalledTimes(1); - expect(logger.info).toHaveBeenCalledWith( - "Updating package.json with version 1.2.3.", - ); - expect(exec).toHaveBeenCalledTimes(5); - }); - - it("doesn't update the package version", async () => { - await updatePackageVersion({ currentVersion: "1.2.3", ...container }); - - expect(logger.warn).toHaveBeenCalledTimes(1); - expect(logger.warn).toHaveBeenCalledWith( - "Version in package.json is already 1.2.3.", - ); - expect(logger.info).not.toHaveBeenCalled(); - expect(exec).not.toHaveBeenCalled(); - }); -}); diff --git a/scripts/specs/uploadToCDN.spec.js b/scripts/specs/uploadToCDN.spec.js deleted file mode 100644 index 06cb5620f..000000000 --- a/scripts/specs/uploadToCDN.spec.js +++ /dev/null @@ -1,62 +0,0 @@ -/* -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 { vi, describe, beforeEach, it, expect } from "vitest"; -import ApplicationError from "../helpers/applicationError.js"; -import uploadToCDN from "../helpers/uploadToCDN.js"; - -describe("uploadToCDN", () => { - let exec; - let logger; - let urlExists; - const version = "1.2.3"; - let container; - - beforeEach(() => { - exec = vi.fn(); - exec.mockReturnValue(Promise.resolve()); - logger = { info: vi.fn() }; - urlExists = vi.fn(); - container = { exec, logger, urlExists, version }; - }); - - it("uploads to CDN", async () => { - urlExists.mockReturnValue(Promise.resolve(true)); - await uploadToCDN(container); - expect(logger.info).toHaveBeenCalledWith("Building files for CDN"); - expect(exec).toHaveBeenCalledWith("build", "pnpm run build"); - expect(logger.info).toHaveBeenCalledWith("Uploading files to CDN."); - expect(exec).toHaveBeenCalledWith("sftp", expect.any(String)); - expect(urlExists).toHaveBeenCalledWith( - "https://cdn1.adoberesources.net/alloy/1.2.3/alloy.js", - ); - expect(urlExists).toHaveBeenCalledWith( - "https://cdn1.adoberesources.net/alloy/1.2.3/alloy.min.js", - ); - }); - - it("fails to upload min file to CDN", async () => { - urlExists - .mockReturnValueOnce(Promise.resolve(false)) - .mockReturnValueOnce(Promise.resolve(true)); - - await expect(uploadToCDN(container)).rejects.toThrow(ApplicationError); - }); - - it("fails to upload regular file to CDN", async () => { - urlExists - .mockReturnValueOnce(Promise.resolve(true)) - .mockReturnValueOnce(Promise.resolve(false)); - - await expect(uploadToCDN(container)).rejects.toThrow(ApplicationError); - }); -}); diff --git a/scripts/specs/withErrorHandling.spec.js b/scripts/specs/withErrorHandling.spec.js deleted file mode 100644 index cac68b756..000000000 --- a/scripts/specs/withErrorHandling.spec.js +++ /dev/null @@ -1,62 +0,0 @@ -/* -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 { vi, describe, beforeEach, it, expect } from "vitest"; -import ApplicationError from "../helpers/applicationError.js"; -import withErrorHandling from "../helpers/withErrorHandling.js"; - -describe("withErrorHandling", () => { - let logger; - let process; - let container; - let func; - - beforeEach(() => { - logger = { info: vi.fn(), error: vi.fn() }; - process = { exit: vi.fn() }; - container = { logger, process }; - func = vi.fn(); - }); - - it("runs without failure", async () => { - func.mockReturnValue(Promise.resolve()); - await withErrorHandling(container, "Deploy", func); - expect(logger.info).toHaveBeenCalledWith("Deploy."); - expect(func).toHaveBeenCalled(); - expect(logger.info).toHaveBeenCalledWith("Deploy COMPLETE."); - }); - - it("handles ApplicationErrors", async () => { - func.mockImplementationOnce(() => { - throw new ApplicationError("myerrormessage"); - }); - await withErrorHandling(container, "Deploy", func); - expect(logger.info).toHaveBeenCalledWith("Deploy."); - expect(logger.error).toHaveBeenCalledWith("Deploy FAILED."); - expect(logger.error).toHaveBeenCalledWith("myerrormessage"); - expect(process.exit).toHaveBeenCalledWith(1); - }); - it("handles unexpected errors", async () => { - const error = new Error("myerrormessage"); - func.mockImplementationOnce(() => { - throw error; - }); - await withErrorHandling(container, "Deploy", func); - expect(logger.info).toHaveBeenCalledWith("Deploy."); - expect(logger.error).toHaveBeenCalledWith("Deploy FAILED."); - expect(logger.error).toHaveBeenCalledWith( - "An unexpected error was thrown.", - error, - ); - expect(process.exit).toHaveBeenCalledWith(1); - }); -}); diff --git a/scripts/uploadToCDN.js b/scripts/uploadToCDN.js new file mode 100755 index 000000000..3e7a6b3d6 --- /dev/null +++ b/scripts/uploadToCDN.js @@ -0,0 +1,61 @@ +#!/usr/bin/env node + +/* +Copyright 2025 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 { execSync } from "child_process"; +import fs from "fs"; +import path from "path"; +import { fileURLToPath } from "url"; + +const filename = fileURLToPath(import.meta.url); +const dirname = path.dirname(filename); +const projectRoot = path.resolve(dirname, ".."); +const distDir = path.join(projectRoot, "dist"); + +const { version } = JSON.parse( + fs.readFileSync(path.join(projectRoot, "package.json"), "utf8"), +); + +if (!version) { + throw new Error("Unable to read package version for CDN upload."); +} + +const requiredFiles = [ + "alloy.js", + "alloy.min.js", + "alloyServiceWorker.js", + "alloyServiceWorker.min.js", +]; + +requiredFiles.forEach((file) => { + const filePath = path.join(distDir, file); + if (!fs.existsSync(filePath)) { + throw new Error(`Missing build artifact for CDN upload: ${filePath}`); + } +}); + +const ftpCommands = `-mkdir ${version} +cd ${version} +put ${path.join(distDir, "alloy.js")} +put ${path.join(distDir, "alloy.min.js")} +put ${path.join(distDir, "alloyServiceWorker.js")} +put ${path.join(distDir, "alloyServiceWorker.min.js")} +bye +`; + +console.log(`Uploading browser artifacts for version ${version} to CDN...`); +execSync( + `echo "${ftpCommands}" | sftp -oHostKeyAlgorithms=+ssh-dss -oStrictHostKeyChecking=no -b - sshacs@dxresources.ssh.upload.akamai.com:/prod/alloy`, + { stdio: "inherit" }, +); +console.log("CDN upload complete."); From b6613ef92664381657939be975cf5bdc89366022 Mon Sep 17 00:00:00 2001 From: Carter McBride <18412686+carterworks@users.noreply.github.com> Date: Mon, 15 Dec 2025 13:08:11 -0700 Subject: [PATCH 10/56] Add changeset file --- .changeset/free-pianos-run.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/free-pianos-run.md diff --git a/.changeset/free-pianos-run.md b/.changeset/free-pianos-run.md new file mode 100644 index 000000000..e8bc9db4d --- /dev/null +++ b/.changeset/free-pianos-run.md @@ -0,0 +1,5 @@ +--- +"@adobe/alloy": patch +--- + +Migrate the release process to use the changesets tool. From ba4dba98ee44ffa9abc39d11b65617c1e545faa3 Mon Sep 17 00:00:00 2001 From: Carter McBride <18412686+carterworks@users.noreply.github.com> Date: Mon, 15 Dec 2025 14:19:10 -0700 Subject: [PATCH 11/56] Add some sanity checks to the url --- .github/workflows/changeset-publish.yml | 41 ++++++++++++++++++++----- 1 file changed, 33 insertions(+), 8 deletions(-) diff --git a/.github/workflows/changeset-publish.yml b/.github/workflows/changeset-publish.yml index a162f6eec..ce4e91624 100644 --- a/.github/workflows/changeset-publish.yml +++ b/.github/workflows/changeset-publish.yml @@ -9,6 +9,7 @@ on: concurrency: changeset-publish-${{ github.ref }} jobs: + # Determine if there are changesets to publish and if we are in prerelease mode. analyze: # Avoid re-running when the bot pushes the version bump commit. if: github.actor != 'github-actions[bot]' @@ -37,17 +38,18 @@ jobs: echo "is_prerelease=false" >> "${GITHUB_OUTPUT}" fi + - name: Setup pnpm + uses: pnpm/action-setup@v4 + with: + version: 10 + - name: Setup Node.js uses: actions/setup-node@v5 with: node-version-file: .nvmrc + cache: pnpm registry-url: https://registry.npmjs.org - - name: Setup pnpm - uses: pnpm/action-setup@v4 - with: - version: 10 - - name: Compute release plan id: release_plan run: | @@ -60,7 +62,8 @@ jobs: fi # `changeset status` writes JSON to the provided filename, relative to cwd. - pnpm dlx @changesets/cli status --output=changeset-status.json + pnpm install --frozen-lockfile + pnpm exec changeset status --output=changeset-status.json HAS_RELEASES=$(node -e "const s=require('./changeset-status.json');console.log((s.releases || []).length > 0 ? 'true' : 'false');") echo "has_releases=${HAS_RELEASES}" >> "${GITHUB_OUTPUT}" @@ -70,7 +73,10 @@ jobs: publish_prerelease: needs: analyze - if: needs.analyze.outputs.has_releases == 'true' && needs.analyze.outputs.is_prerelease == 'true' + if: >- + github.ref == 'refs/heads/main' && + needs.analyze.outputs.has_releases == 'true' && + needs.analyze.outputs.is_prerelease == 'true' runs-on: ubuntu-latest permissions: contents: write @@ -80,6 +86,14 @@ jobs: with: fetch-depth: 0 + - name: Verify main has not moved + run: | + git fetch origin main + if [ "$(git rev-parse HEAD)" != "$(git rev-parse origin/main)" ]; then + echo "::error::origin/main has moved since this workflow started. Aborting to avoid conflicts." + exit 1 + fi + - name: Setup pnpm uses: pnpm/action-setup@v4 with: @@ -142,7 +156,10 @@ jobs: publish_release: needs: analyze - if: needs.analyze.outputs.has_releases == 'true' && needs.analyze.outputs.is_prerelease != 'true' + if: >- + github.ref == 'refs/heads/main' && + needs.analyze.outputs.has_releases == 'true' && + needs.analyze.outputs.is_prerelease != 'true' runs-on: ubuntu-latest # Stable releases require a manual approval. environment: Production @@ -154,6 +171,14 @@ jobs: with: fetch-depth: 0 + - name: Verify main has not moved + run: | + git fetch origin main + if [ "$(git rev-parse HEAD)" != "$(git rev-parse origin/main)" ]; then + echo "::error::origin/main has moved since this workflow started. Aborting to avoid conflicts." + exit 1 + fi + - name: Setup pnpm uses: pnpm/action-setup@v4 with: From d3e88ce2ec9a3accc3dbef428f71f7e9b2cd3d07 Mon Sep 17 00:00:00 2001 From: Carter McBride <18412686+carterworks@users.noreply.github.com> Date: Mon, 15 Dec 2025 14:30:24 -0700 Subject: [PATCH 12/56] Add some sanity checks to the CDN upload --- scripts/uploadToCDN.js | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/scripts/uploadToCDN.js b/scripts/uploadToCDN.js index 3e7a6b3d6..f1f8c7bc4 100755 --- a/scripts/uploadToCDN.js +++ b/scripts/uploadToCDN.js @@ -16,6 +16,7 @@ import { execSync } from "child_process"; import fs from "fs"; import path from "path"; import { fileURLToPath } from "url"; +import urlExists from "url-exists-nodejs"; const filename = fileURLToPath(import.meta.url); const dirname = path.dirname(filename); @@ -59,3 +60,40 @@ execSync( { stdio: "inherit" }, ); console.log("CDN upload complete."); + +const cdnBase = `https://cdn1.adoberesources.net/alloy/${version}`; +const verifyUrls = [`${cdnBase}/alloy.js`, `${cdnBase}/alloy.min.js`]; + +/** + * @param {string[]} urls + * @returns {Promise<{ url: string, exists: boolean }[]>} + */ +const verifyCdnEndpoints = async (urls) => { + const results = await Promise.allSettled( + urls.map(async (url) => { + const exists = await urlExists(url); + return { url, exists }; + }), + ); + + return results.map((result, index) => { + if (result.status === "fulfilled") { + return result.value; + } + // If the promise was rejected, return exists: false + return { url: urls[index], exists: false }; + }); +}; +console.log("Verifying CDN endpoints..."); +const results = await verifyCdnEndpoints(verifyUrls); +console.log(JSON.stringify(results, null, 2)); +if (results.some((result) => !result.exists)) { + throw new Error( + "CDN endpoint verification failed for urls: " + + results + .filter((result) => !result.exists) + .map((result) => result.url) + .join(", "), + ); +} +console.log("CDN endpoint verification complete."); From fc98dbb4502d57ac15219eda77d65101ce278049 Mon Sep 17 00:00:00 2001 From: Carter McBride <18412686+carterworks@users.noreply.github.com> Date: Mon, 15 Dec 2025 16:26:15 -0700 Subject: [PATCH 13/56] Init browser package --- package.json | 5 ++--- packages/browser/package.json | 13 +++++++++++++ packages/core/package.json | 3 +-- 3 files changed, 16 insertions(+), 5 deletions(-) create mode 100644 packages/browser/package.json diff --git a/package.json b/package.json index e73826f10..6785d7934 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,6 @@ { - "name": "@adobe/alloy", - "version": "2.30.1-beta.15", - "description": "Adobe Experience Platform Web SDK", + "name": "adobe-alloy-monorepo", + "version": "0.0.1", "type": "module", "main": "libEs5/index.js", "module": "libEs6/index.js", diff --git a/packages/browser/package.json b/packages/browser/package.json new file mode 100644 index 000000000..30ad77c41 --- /dev/null +++ b/packages/browser/package.json @@ -0,0 +1,13 @@ +{ + "name": "@adobe/alloy", + "version": "2.30.1-beta.4", + "description": "Adobe Experience Platform Web SDK", + "type": "module", + "repository": { + "type": "git", + "url": "git+https://github.com/adobe/alloy.git", + "directory": "packages/browser" + }, + "author": "Adobe Inc.", + "license": "Apache-2.0" +} diff --git a/packages/core/package.json b/packages/core/package.json index 3a222a899..ef10c9202 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,9 +1,8 @@ { "name": "@adobe/alloy-core", - "version": "2.29.0-beta.1", + "version": "1.1.0", "description": "Adobe Experience Platform Web SDK Core (Internal Package)", "type": "module", - "private": true, "repository": { "type": "git", "url": "git+https://github.com/adobe/alloy.git", From ac5c52d481b4acae6fd52acdcddbb955c2eef38b Mon Sep 17 00:00:00 2001 From: Carter McBride <18412686+carterworks@users.noreply.github.com> Date: Thu, 30 Oct 2025 12:21:22 -0600 Subject: [PATCH 14/56] Move baseCode and index to browser package --- eslint.config.js | 2 +- packages/browser/package.json | 10 +++++++++- packages/{core => browser}/src/baseCode.js | 0 packages/{core => browser}/src/baseCode/index.js | 0 packages/browser/src/index.js | 14 ++++++++++++++ packages/core/src/index.js | 2 -- pnpm-lock.yaml | 8 +++++++- 7 files changed, 31 insertions(+), 5 deletions(-) rename packages/{core => browser}/src/baseCode.js (100%) rename packages/{core => browser}/src/baseCode/index.js (100%) create mode 100644 packages/browser/src/index.js diff --git a/eslint.config.js b/eslint.config.js index cf98e5c42..47569098d 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -144,7 +144,7 @@ export default defineConfig([ }, { name: "alloy/core-src", - files: ["packages/core/src/**/*.{cjs,js}"], + files: ["packages/*/src/**/*.{cjs,js}"], rules: { "import/no-extraneous-dependencies": [ "error", diff --git a/packages/browser/package.json b/packages/browser/package.json index 30ad77c41..6cbdcad5f 100644 --- a/packages/browser/package.json +++ b/packages/browser/package.json @@ -9,5 +9,13 @@ "directory": "packages/browser" }, "author": "Adobe Inc.", - "license": "Apache-2.0" + "license": "Apache-2.0", + "exports": { + ".": "./src/index.js", + "./baseCode.js": "./src/baseCode/index.js", + "./standalone.js": "./src/baseCode.js" + }, + "dependencies": { + "@adobe/alloy-core": "workspace:^" + } } diff --git a/packages/core/src/baseCode.js b/packages/browser/src/baseCode.js similarity index 100% rename from packages/core/src/baseCode.js rename to packages/browser/src/baseCode.js diff --git a/packages/core/src/baseCode/index.js b/packages/browser/src/baseCode/index.js similarity index 100% rename from packages/core/src/baseCode/index.js rename to packages/browser/src/baseCode/index.js diff --git a/packages/browser/src/index.js b/packages/browser/src/index.js new file mode 100644 index 000000000..7fb66df63 --- /dev/null +++ b/packages/browser/src/index.js @@ -0,0 +1,14 @@ +import * as core from "@adobe/alloy-core"; + +const components = core.components; +export { components }; + +/** @type {core.createCustomInstance} */ +export const createCustomInstance = (options) => { + return core.createCustomInstance(options); +}; + +/** @type {core.createInstance} */ +export const createInstance = (options) => { + return core.createInstance(options); +}; diff --git a/packages/core/src/index.js b/packages/core/src/index.js index 6f8d39073..6fb9ee8ed 100644 --- a/packages/core/src/index.js +++ b/packages/core/src/index.js @@ -29,8 +29,6 @@ import { import getMonitors from "./core/getMonitors.js"; import * as optionalComponents from "./core/componentCreators.js"; -export { default as baseCode } from "./baseCode/index.js"; - const { console } = window; const createNamespacedStorage = injectStorage(window); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a1393b954..07e413a1d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -56,7 +56,7 @@ importers: devDependencies: '@adobe/alloy': specifier: next - version: 'link:' + version: link:packages/browser '@babel/cli': specifier: ^7.28.3 version: 7.28.3(@babel/core@7.28.5) @@ -167,6 +167,12 @@ importers: specifier: ^4.52.5 version: 4.52.5 + packages/browser: + dependencies: + '@adobe/alloy-core': + specifier: workspace:^ + version: link:../core + packages/core: dependencies: '@adobe/aep-rules-engine': From da1d61a87c2b0d51b3e0bce1d36813db567b3d92 Mon Sep 17 00:00:00 2001 From: Carter McBride <18412686+carterworks@users.noreply.github.com> Date: Thu, 30 Oct 2025 12:25:40 -0600 Subject: [PATCH 15/56] Migrate service worker --- packages/browser/package.json | 3 +- packages/browser/src/index.js | 11 +++ .../{core => browser}/src/serviceWorker.js | 34 ++++------ packages/core/package.json | 3 +- packages/core/src/createEventListeners.js | 68 +++++++++++++++++++ 5 files changed, 95 insertions(+), 24 deletions(-) rename packages/{core => browser}/src/serviceWorker.js (64%) create mode 100644 packages/core/src/createEventListeners.js diff --git a/packages/browser/package.json b/packages/browser/package.json index 6cbdcad5f..1aefb6225 100644 --- a/packages/browser/package.json +++ b/packages/browser/package.json @@ -13,7 +13,8 @@ "exports": { ".": "./src/index.js", "./baseCode.js": "./src/baseCode/index.js", - "./standalone.js": "./src/baseCode.js" + "./standalone.js": "./src/baseCode.js", + "./serviceWorker.js": "./src/serviceWorker.js" }, "dependencies": { "@adobe/alloy-core": "workspace:^" diff --git a/packages/browser/src/index.js b/packages/browser/src/index.js index 7fb66df63..a5377b180 100644 --- a/packages/browser/src/index.js +++ b/packages/browser/src/index.js @@ -1,3 +1,14 @@ +/* +Copyright 2025 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 * as core from "@adobe/alloy-core"; const components = core.components; diff --git a/packages/core/src/serviceWorker.js b/packages/browser/src/serviceWorker.js similarity index 64% rename from packages/core/src/serviceWorker.js rename to packages/browser/src/serviceWorker.js index 87bae2c1b..f0e61af81 100644 --- a/packages/core/src/serviceWorker.js +++ b/packages/browser/src/serviceWorker.js @@ -10,14 +10,9 @@ OF ANY KIND, either express or implied. See the License for the specific languag governing permissions and limitations under the License. */ -/** @import { ServiceWorkerLogger } from './components/PushNotifications/types.js' */ - -import serviceWorkerNotificationClickListener from "./components/PushNotifications/helpers/serviceWorkerNotificationClickListener.js"; -import serviceWorkerPushListener from "./components/PushNotifications/helpers/serviceWorkerPushListener.js"; -import makeSendServiceWorkerTrackingData from "./components/PushNotifications/request/makeSendServiceWorkerTrackingData.js"; +import createEventListeners from "@adobe/alloy-core/createEventListeners.js"; /* eslint-disable no-console */ -/* eslint-disable no-underscore-dangle */ // @ts-check /// @@ -35,6 +30,14 @@ const logger = { error: (...args) => console.error(logger.namespace, ...args), }; +const eventListeners = createEventListeners({ + sw, + platform: { + logger, + fetch, + }, +}); + /** * @listens install */ @@ -56,7 +59,7 @@ sw.addEventListener("activate", (event) => { * @returns {Promise} */ sw.addEventListener("push", (event) => - serviceWorkerPushListener({ event, logger, sw }), + eventListeners.pushNotifications.onPush(event), ); /** @@ -64,7 +67,7 @@ sw.addEventListener("push", (event) => * @param {NotificationEvent} event */ sw.addEventListener("notificationclick", (event) => - serviceWorkerNotificationClickListener({ event, sw, logger, fetch }), + eventListeners.pushNotifications.onNotificationClick(event), ); /** @@ -72,18 +75,5 @@ sw.addEventListener("notificationclick", (event) => * @param {NotificationEvent} event */ sw.addEventListener("notificationclose", (event) => { - const data = event.notification.data; - - makeSendServiceWorkerTrackingData( - { - xdm: data._xdm.mixins, - actionLabel: "Dismiss", - }, - { - logger, - fetch, - }, - ).catch((error) => { - logger.error("Failed to send tracking call:", error); - }); + eventListeners.pushNotifications.onNotificationClose(event); }); diff --git a/packages/core/package.json b/packages/core/package.json index ef10c9202..30e70217f 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -9,7 +9,8 @@ "directory": "packages/core" }, "exports": { - ".": "./src/index.js" + ".": "./src/index.js", + "./createEventListeners.js": "./src/createEventListeners.js" }, "author": "Adobe Inc.", "license": "Apache-2.0", diff --git a/packages/core/src/createEventListeners.js b/packages/core/src/createEventListeners.js new file mode 100644 index 000000000..af13ed84e --- /dev/null +++ b/packages/core/src/createEventListeners.js @@ -0,0 +1,68 @@ +/* +Copyright 2025 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 serviceWorkerPushListener from "./components/PushNotifications/helpers/serviceWorkerPushListener.js"; +import serviceWorkerNotificationClickListener from "./components/PushNotifications/helpers/serviceWorkerNotificationClickListener.js"; +import makeSendServiceWorkerTrackingData from "./components/PushNotifications/request/makeSendServiceWorkerTrackingData.js"; + +/** + * @type {Object} PlatformCapabilities + * @property {Logger} logger + * + * TODO: Remove dependency on sw (service worker) + */ +const createEventListeners = ({ platform, sw }) => { + return { + pushNotifications: { + /** + * + * @param {PushEvent} event + * @returns Promise + */ + onPush(event) { + return serviceWorkerPushListener({ + event, + sw, + logger: platform.logger, + }); + }, + /** + * @param {NotificationEvent} event + */ + onNotificationClick(event) { + serviceWorkerNotificationClickListener({ + event, + sw, + logger: platform.logger, + fetch: platform.fetch, + }); + }, + /** + * + * @param {NotificationEvent} event + */ + async onNotificationClose(event) { + const data = event.notification.data; + + try { + await makeSendServiceWorkerTrackingData({ + /* eslint-disable-next-line no-underscore-dangle */ + xdm: data._xdm.mixins, + actionLabel: "Dismiss", + }); + } catch (error) { + platform.logger.error("Failed to send tracking call:", error); + } + }, + }, + }; +}; +export default createEventListeners; From c480377a997abf02e8dd81c2a228b7071ba9f595 Mon Sep 17 00:00:00 2001 From: Carter McBride <18412686+carterworks@users.noreply.github.com> Date: Thu, 30 Oct 2025 14:08:53 -0600 Subject: [PATCH 16/56] Migrate standalone.js --- packages/browser/src/standalone.js | 37 ++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 packages/browser/src/standalone.js diff --git a/packages/browser/src/standalone.js b/packages/browser/src/standalone.js new file mode 100644 index 000000000..af6e5dd56 --- /dev/null +++ b/packages/browser/src/standalone.js @@ -0,0 +1,37 @@ +/* +Copyright 2025 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 { + createCustomInstance, + components as optionalComponents, +} from "./index.js"; + +// This file is used by rollup to create the browser version that is uploaded to cdn + +const initializeStandalone = async ({ components }) => { + // eslint-disable-next-line no-underscore-dangle + const instanceNames = window.__alloyNS; + if (!instanceNames) { + return; + } + for (const name of instanceNames) { + const instance = createCustomInstance({ name, components }); + const execute = ([resolve, reject, [commandName, options]]) => + instance(commandName, options).then(resolve, reject); + const queue = window[name].q; + queue.push = execute; + queue.forEach(execute); + } +}; + +// If you change this line, check if the custom build script is still working. +// You might need to change the babel plugin in scripts/helpers/entryPointGeneratorBabelPlugin.js. +initializeStandalone({ components: Object.values(optionalComponents) }); From d84e101370113d757138b8d242277569e1947dc4 Mon Sep 17 00:00:00 2001 From: Carter McBride <18412686+carterworks@users.noreply.github.com> Date: Thu, 30 Oct 2025 15:06:49 -0600 Subject: [PATCH 17/56] Migrate the build --- package.json | 10 +- packages/browser/LICENSE_BANNER | 9 + packages/browser/babel.config.js | 76 +++++ packages/browser/bundlesize.json | 32 ++ packages/browser/package.json | 17 ++ packages/browser/rollup.config.js | 289 ++++++++++++++++++ .../scripts/helpers/versionBabelPlugin.js | 42 +++ .../functional/helpers/npmPackageLocal.js | 15 + .../test/functional/helpers/npmPackageProd.js | 17 ++ pnpm-lock.yaml | 145 ++++----- rollup.config.js | 29 +- 11 files changed, 568 insertions(+), 113 deletions(-) create mode 100644 packages/browser/LICENSE_BANNER create mode 100644 packages/browser/babel.config.js create mode 100644 packages/browser/bundlesize.json create mode 100644 packages/browser/rollup.config.js create mode 100644 packages/browser/scripts/helpers/versionBabelPlugin.js create mode 100644 packages/browser/test/functional/helpers/npmPackageLocal.js create mode 100644 packages/browser/test/functional/helpers/npmPackageProd.js diff --git a/package.json b/package.json index 6785d7934..86ff9cbde 100644 --- a/package.json +++ b/package.json @@ -39,12 +39,12 @@ "test:functional:custom": "node scripts/helpers/runFunctionalTests.js", "test:functional:watch": "pnpm exec playwright install chromium && EDGE_BASE_PATH=\"ee-pre-prd\" ALLOY_ENV=\"int\" ./scripts/watchFunctionalTests.js --browsers chromium", "test:functional:debug": "pnpm exec playwright install chromium && EDGE_BASE_PATH=\"ee-pre-prd\" ALLOY_ENV=\"int\" testcafe --inspect-brk chromium", - "test:functional:build:int": "rollup -c --environment BASE_CODE_MIN,STANDALONE,NPM_PACKAGE_LOCAL", - "test:functional:build:prod": "rollup -c --environment BASE_CODE_MIN,NPM_PACKAGE_PROD", + "test:functional:build:int": "pnpm --filter @adobe/alloy test:functional:build:int", + "test:functional:build:prod": "pnpm --filter @adobe/alloy test:functional:build:prod", "test:scripts": "vitest run --config=./scripts/specs/vitest.config.js", - "dev": "concurrently --names build,sandbox \"rollup -c -w --environment SANDBOX_SERVICE_WORKER\" \"REACT_APP_NONCE=123 pnpm run --filter @adobe/alloy-sandbox-browser start\"", - "build": "pnpm run clean && rollup -c --environment BASE_CODE_MIN,STANDALONE,STANDALONE_MIN,SERVICE_WORKER,SERVICE_WORKER_MIN,BUNDLESIZE && echo \"Base Code:\" && cat distTest/baseCode.min.js", - "build:watch": "pnpm run clean && rollup -c --watch --environment BASE_CODE_MIN,STANDALONE", + "dev": "REACT_APP_NONCE=123 pnpm run --filter @adobe/alloy-sandbox-browser start", + "build": "pnpm --filter @adobe/alloy build", + "build:watch": "pnpm --filter @adobe/alloy build:watch", "build:custom": "node scripts/alloyBuilder.js", "prepare": "husky", "prepack": "pnpm run clean && babel packages/core/src -d libEs5 --env-name npmEs5 && babel packages/core/src -d libEs6 --env-name npmEs6 && echo '{\"type\":\"commonjs\"}' > libEs5/package.json && echo '{\"type\":\"module\"}' > libEs6/package.json && pnpm run types", diff --git a/packages/browser/LICENSE_BANNER b/packages/browser/LICENSE_BANNER new file mode 100644 index 000000000..34ed6b2da --- /dev/null +++ b/packages/browser/LICENSE_BANNER @@ -0,0 +1,9 @@ +Copyright 2019 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. diff --git a/packages/browser/babel.config.js b/packages/browser/babel.config.js new file mode 100644 index 000000000..472f39aa9 --- /dev/null +++ b/packages/browser/babel.config.js @@ -0,0 +1,76 @@ +/* +Copyright 2021 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. +*/ + +/* + * This file is used in 4 scenarios: + * 1. Building files specified in rollup.config.js + * 2. Building libEs5/ files when publishing to NPM + * 3. Building libEs6/ files when publishing to NPM + * 4. Testcafe compiling clientFunctions. Unfortunately, there is no configuration I've found + * to tell Testcafe not to use this file. + * + * Environments: + * "rollup" - Used for rollup.config.js + * "npmEs5" - Used for building libEs5 files when publishing to NPM + * "npmEs6" - Used for building libEs6 files when publishing to NPM + */ +import { dirname } from "path"; +import { fileURLToPath } from "url"; + +const cwd = dirname(fileURLToPath(import.meta.url)); + +const transformTemplateLiteralsPlugin = [ + "@babel/plugin-transform-template-literals", + { + loose: true, + }, +]; +const versionPlugin = ["./scripts/helpers/versionBabelPlugin", { cwd }]; + +const transformModulesCommonjsPlugin = [ + "@babel/plugin-transform-modules-commonjs", + { + strict: true, + noInterop: true, + }, +]; + +const npmIgnoreFiles = ["src/baseCode.js"]; + +export default { + env: { + rollup: { + presets: [ + [ + "@babel/preset-env", + { + modules: false, + }, + ], + ], + plugins: [transformTemplateLiteralsPlugin, versionPlugin], + }, + npmEs5: { + presets: [["@babel/preset-env"]], + ignore: npmIgnoreFiles, + plugins: [ + transformTemplateLiteralsPlugin, + versionPlugin, + transformModulesCommonjsPlugin, + ], + }, + npmEs6: { + ignore: npmIgnoreFiles, + plugins: [versionPlugin], + }, + }, +}; diff --git a/packages/browser/bundlesize.json b/packages/browser/bundlesize.json new file mode 100644 index 000000000..c5493fde8 --- /dev/null +++ b/packages/browser/bundlesize.json @@ -0,0 +1,32 @@ +{ + "distTest/baseCode.min.js": { + "uncompressedSize": 199, + "gzippedSize": 164, + "brotiliSize": 133 + }, + "/Users/cmcbride/homebase/code/github.com/adobe/alloy/.worktrees/alloy-browser-package/packages/browser/distTest/baseCode.min.js": { + "uncompressedSize": 199, + "gzippedSize": 164, + "brotiliSize": 133 + }, + "/Users/cmcbride/homebase/code/github.com/adobe/alloy/.worktrees/alloy-browser-package/packages/browser/dist/alloy.js": { + "uncompressedSize": 699826, + "gzippedSize": 112126, + "brotiliSize": 86457 + }, + "/Users/cmcbride/homebase/code/github.com/adobe/alloy/.worktrees/alloy-browser-package/packages/browser/dist/alloy.min.js": { + "uncompressedSize": 145497, + "gzippedSize": 48086, + "brotiliSize": 41687 + }, + "/Users/cmcbride/homebase/code/github.com/adobe/alloy/.worktrees/alloy-browser-package/packages/browser/dist/alloyServiceWorker.js": { + "uncompressedSize": 18201, + "gzippedSize": 4287, + "brotiliSize": 3633 + }, + "/Users/cmcbride/homebase/code/github.com/adobe/alloy/.worktrees/alloy-browser-package/packages/browser/dist/alloyServiceWorker.min.js": { + "uncompressedSize": 5542, + "gzippedSize": 2589, + "brotiliSize": 2184 + } +} \ No newline at end of file diff --git a/packages/browser/package.json b/packages/browser/package.json index 1aefb6225..139cc5e8d 100644 --- a/packages/browser/package.json +++ b/packages/browser/package.json @@ -10,6 +10,11 @@ }, "author": "Adobe Inc.", "license": "Apache-2.0", + "scripts": { + "build:clean": "rimraf dist distTest", + "build": "pnpm run build:clean && rollup -c --environment BASE_CODE_MIN,STANDALONE,STANDALONE_MIN,SERVICE_WORKER,SERVICE_WORKER_MIN,BUNDLESIZE", + "build:watch": "rollup -c --watch" + }, "exports": { ".": "./src/index.js", "./baseCode.js": "./src/baseCode/index.js", @@ -18,5 +23,17 @@ }, "dependencies": { "@adobe/alloy-core": "workspace:^" + }, + "devDependencies": { + "@babel/core": "^7.28.5", + "@babel/plugin-transform-template-literals": "^7.27.1", + "@babel/preset-env": "^7.28.5", + "@rollup/plugin-babel": "^6.1.0", + "@rollup/plugin-commonjs": "^28.0.9", + "@rollup/plugin-node-resolve": "^16.0.3", + "@rollup/plugin-terser": "^0.4.4", + "rimraf": "^6.0.1", + "rollup": "^4.52.5", + "rollup-plugin-license": "^3.6.0" } } diff --git a/packages/browser/rollup.config.js b/packages/browser/rollup.config.js new file mode 100644 index 000000000..d1da62262 --- /dev/null +++ b/packages/browser/rollup.config.js @@ -0,0 +1,289 @@ +/* +Copyright 2019 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 path from "path"; +import resolve from "@rollup/plugin-node-resolve"; +import commonjs from "@rollup/plugin-commonjs"; +import babel from "@rollup/plugin-babel"; +import terser from "@rollup/plugin-terser"; +import license from "rollup-plugin-license"; +import { fileURLToPath } from "url"; +import { gzip, brotliCompress as br, constants as zlibConstants } from "zlib"; +import { promisify } from "util"; +import { readFile, writeFile } from "fs/promises"; + +const INCLUDE_BUNDLESIZE = process.env.BUNDLESIZE === "true"; +/** + * @param {Object} options + * @param {string} [options.outputFile] Filepath to output the bundle size report. + * @param {boolean} [options.reportToConsole] Whether to log the bundle size report to the console in addition to writing it to a file. + * @param {number} [options.gzipCompressionLevel] The compression level to use when gzipping the bundle. + * @param {number} [options.brotliCompressionLevel] The compression level to use when brotli-compressing the bundle. + * @returns {Partial} + */ +const bundleSizePlugin = (_options = {}) => { + const defaultOptions = { + outputFile: "bundlesize.json", + reportToConsole: false, + gzipCompressionLevel: zlibConstants.Z_DEFAULT_COMPRESSION, + brotliCompressionLevel: zlibConstants.BROTLI_DEFAULT_QUALITY, + }; + const options = { ...defaultOptions, ..._options }; + const gzipCompress = promisify(gzip); + const brotliCompress = promisify(br); + /** + * @param {import("node:zlib").InputType} source the source code to compress + * @param {import("node:zlib").ZlibOptions={}} options + * @returns {number} size in bytes + */ + const getGzippedSize = async (source, opts = {}) => { + const compressed = await gzipCompress(source, opts); + const byteSize = Number.parseInt(compressed.byteLength, 10); + return byteSize; + }; + /** + * @param {import("node:zlib").InputType} source the source code to compress + * @param {import("node:zlib").BrotliOptions={}} options + * @returns {number} size in bytes + */ + const getBrotiliSize = async (source, opts = {}) => { + const compressed = await brotliCompress(source, opts); + const byteSize = Number.parseInt(compressed.byteLength, 10); + return byteSize; + }; + return { + name: "bundle-size", + generateBundle: { + order: "post", + /** + * @param {import("rollup").NormalizedOutputOptions} rollupOptions + * @param {import("rollup").OutputBundle} bundle + * @returns {Promise} + */ + async handler(rollupOptions, bundle) { + // keep sizes in bytes until displaying them + const sizes = await Promise.all( + Object.values(bundle) + .filter((outputFile) => outputFile.type === "chunk") + .map(async (chunk) => ({ + fileName: rollupOptions.file, + uncompressedSize: Buffer.from(chunk.code).byteLength, + gzippedSize: await getGzippedSize(chunk.code, { + level: options.gzipCompressionLevel, + }), + brotiliSize: await getBrotiliSize(chunk.code, { + params: { + [zlibConstants.BROTLI_PARAM_QUALITY]: + options.brotliCompressionLevel, + }, + }), + })), + ); + if (options.reportToConsole) { + // eslint-disable-next-line no-console + console.table(sizes); + } + // check if the output file exists, create it if it does not exist + let report = {}; + try { + const outputFile = readFile(path.resolve(options.outputFile)); + report = JSON.parse(await outputFile); + } catch { + // ignore errors. They are probably due to the file not existing + } + // update the report with the new sizes + sizes + // stable sort the report by filename + .sort(({ fileName: a }, { fileName: b }) => a.localeCompare(b)) + .forEach((size) => { + const { fileName } = size; + delete size.fileName; + report[fileName] = size; + }); + // write the report to the file + await writeFile( + path.resolve(options.outputFile), + JSON.stringify(report, null, 2), + ); + }, + }, + }; +}; +// Set these boolean environment options to control which files are built: +// build the snippet that must be add to the page +const BASE_CODE = "BASE_CODE"; +// build the standalone distribution +const STANDALONE = "STANDALONE"; +// build the npm package entrypoint (createInstance) +const NPM_PACKAGE_LOCAL = "NPM_PACKAGE_LOCAL"; +// build from the published npm package +const NPM_PACKAGE_PROD = "NPM_PACKAGE_PROD"; +// build the standalone distrobution, but exclude some (specified) modules +const CUSTOM_BUILD = "CUSTOM_BUILD"; +// build the service worker (used for push notifications feature). +const SERVICE_WORKER = "SERVICE_WORKER"; +// Add "_MIN" to the end of the option name to build the minified version + +const dirname = path.dirname(fileURLToPath(import.meta.url)); + +const buildPlugins = ({ variant, minify, babelPlugins }) => { + const plugins = [ + resolve({ + preferBuiltins: false, + // Support the browser field in dependencies' package.json. + // Useful for the uuid package. + mainFields: ["module", "main", "browser"], + }), + commonjs(), + ]; + + if (variant !== SERVICE_WORKER) { + plugins.push( + babel({ + envName: "rollup", + babelHelpers: "bundled", + configFile: path.resolve(dirname, "babel.config.js"), + plugins: babelPlugins, + }), + ); + } + + if (INCLUDE_BUNDLESIZE) { + plugins.push( + bundleSizePlugin({ + outputFile: path.resolve(dirname, "bundlesize.json"), + }), + ); + } + + if (minify) { + if (variant === BASE_CODE) { + plugins.push( + terser({ + mangle: true, + compress: { + unused: true, + }, + output: { + wrap_func_args: false, + }, + toplevel: true, + }), + ); + } else { + plugins.push(terser()); + } + } + if ( + variant === STANDALONE || + variant === CUSTOM_BUILD || + variant === SERVICE_WORKER + ) { + plugins.push( + license({ + cwd: dirname, + banner: { + content: { + file: path.join(dirname, "LICENSE_BANNER"), + }, + }, + }), + ); + } + + return plugins; +}; + +export const buildConfig = ({ + variant = STANDALONE, + minify = false, + babelPlugins = [], + input = `${dirname}/src/standalone.js`, + file, +}) => { + const plugins = buildPlugins({ variant, minify, babelPlugins }); + const minifiedExtension = minify ? ".min" : ""; + + if (variant === SERVICE_WORKER) { + return { + input: `${dirname}/src/serviceWorker.js`, + output: [ + { + file: file || `${dirname}/dist/alloyServiceWorker${minifiedExtension}.js`, + format: "es", + }, + ], + plugins, + }; + } + + if (variant === BASE_CODE) { + return { + input: `${dirname}/src/baseCode.js`, + output: [ + { + file: `${dirname}/distTest/baseCode${minifiedExtension}.js`, + format: "cjs", + strict: false, + }, + ], + plugins, + }; + } + + if (variant === STANDALONE || variant === CUSTOM_BUILD) { + return { + input, + output: [ + { + file: file || `${dirname}/dist/alloy${minifiedExtension}.js`, + format: "iife", + }, + ], + plugins, + }; + } + + // NPM_PACKAGE_LOCAL or NPM_PACKAGE_PROD + const filename = + variant === NPM_PACKAGE_LOCAL ? "npmPackageLocal" : "npmPackageProd"; + + return { + input: `${dirname}/test/functional/helpers/${filename}.js`, + output: [ + { + file: `${dirname}/distTest/${filename}${minifiedExtension}.js`, + format: "iife", + }, + ], + plugins, + }; +}; + +const config = []; + +const addConfig = (variant) => { + if (process.env[variant]) { + config.push(buildConfig({ variant, minify: false })); + } + if (process.env[`${variant}_MIN`]) { + config.push(buildConfig({ variant, minify: true })); + } +}; + +addConfig(BASE_CODE); +addConfig(STANDALONE); +addConfig(NPM_PACKAGE_LOCAL); +addConfig(NPM_PACKAGE_PROD); +addConfig(SERVICE_WORKER); + +export default config; diff --git a/packages/browser/scripts/helpers/versionBabelPlugin.js b/packages/browser/scripts/helpers/versionBabelPlugin.js new file mode 100644 index 000000000..49819c6a6 --- /dev/null +++ b/packages/browser/scripts/helpers/versionBabelPlugin.js @@ -0,0 +1,42 @@ +import { createRequire } from "module"; + +const require = createRequire(import.meta.url); + +const version = null; +const getVersion = ({ opts: { cwd } }) => { + if (version) { + return version; + } + + const packageJson = require(`${cwd}/package.json`); + return packageJson.version; +}; + +export default (_ref) => { + const t = _ref.types; + + return { + visitor: { + // __VERSION__ + ReferencedIdentifier(path, state) { + const identifier = state.opts.identifier; + const transform = identifier === undefined ? true : identifier; + + const define = state.opts.define || "__VERSION__"; + if (transform && path.node.name === define) { + path.replaceWith(t.valueToNode(getVersion(state))); + } + }, + // "__VERSION__" + StringLiteral(path, state) { + const stringLiteral = state.opts.stringLiteral; + const transform = stringLiteral === undefined ? true : stringLiteral; + + const define = state.opts.define || "__VERSION__"; + if (transform && path.node.value === define) { + path.replaceWith(t.valueToNode(getVersion(state))); + } + }, + }, + }; +}; diff --git a/packages/browser/test/functional/helpers/npmPackageLocal.js b/packages/browser/test/functional/helpers/npmPackageLocal.js new file mode 100644 index 000000000..b583123d3 --- /dev/null +++ b/packages/browser/test/functional/helpers/npmPackageLocal.js @@ -0,0 +1,15 @@ +/* +Copyright 2020 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 { createInstance } from "../../../src/index.js"; + +window.alloyCreateInstance = createInstance; diff --git a/packages/browser/test/functional/helpers/npmPackageProd.js b/packages/browser/test/functional/helpers/npmPackageProd.js new file mode 100644 index 000000000..7a7048adf --- /dev/null +++ b/packages/browser/test/functional/helpers/npmPackageProd.js @@ -0,0 +1,17 @@ +/* +Copyright 2020 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. +*/ + +// eslint-disable-next-line import/no-unresolved +// FIXME: Self-dependency is broken in monorepo, so this does not currently work. +import { createInstance } from "@adobe/alloy"; + +window.alloyCreateInstance = createInstance; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 07e413a1d..2bee0a942 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -172,6 +172,37 @@ importers: '@adobe/alloy-core': specifier: workspace:^ version: link:../core + devDependencies: + '@babel/core': + specifier: ^7.28.5 + version: 7.28.5 + '@babel/plugin-transform-template-literals': + specifier: ^7.27.1 + version: 7.27.1(@babel/core@7.28.5) + '@babel/preset-env': + specifier: ^7.28.5 + version: 7.28.5(@babel/core@7.28.5) + '@rollup/plugin-babel': + specifier: ^6.1.0 + version: 6.1.0(@babel/core@7.28.5)(@types/babel__core@7.20.5)(rollup@4.52.5) + '@rollup/plugin-commonjs': + specifier: ^28.0.9 + version: 28.0.9(rollup@4.52.5) + '@rollup/plugin-node-resolve': + specifier: ^16.0.3 + version: 16.0.3(rollup@4.52.5) + '@rollup/plugin-terser': + specifier: ^0.4.4 + version: 0.4.4(rollup@4.52.5) + rimraf: + specifier: ^6.0.1 + version: 6.0.1 + rollup: + specifier: ^4.52.5 + version: 4.52.5 + rollup-plugin-license: + specifier: ^3.6.0 + version: 3.6.0(picomatch@4.0.3)(rollup@4.52.5) packages/core: dependencies: @@ -239,10 +270,6 @@ packages: resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} engines: {node: '>=6.9.0'} - '@babel/compat-data@7.28.4': - resolution: {integrity: sha512-YsmSKC29MJwf0gF8Rjjrg5LQCmyh+j/nD8/eP7f+BeoQTKYqs9RoWbjGOdy0+1Ekr68RJZMUOPVQaQisnIo4Rw==} - engines: {node: '>=6.9.0'} - '@babel/compat-data@7.28.5': resolution: {integrity: sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==} engines: {node: '>=6.9.0'} @@ -251,10 +278,6 @@ packages: resolution: {integrity: sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==} engines: {node: '>=6.9.0'} - '@babel/generator@7.28.3': - resolution: {integrity: sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==} - engines: {node: '>=6.9.0'} - '@babel/generator@7.28.5': resolution: {integrity: sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==} engines: {node: '>=6.9.0'} @@ -340,10 +363,6 @@ packages: resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} engines: {node: '>=6.9.0'} - '@babel/helper-validator-identifier@7.27.1': - resolution: {integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==} - engines: {node: '>=6.9.0'} - '@babel/helper-validator-identifier@7.28.5': resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} engines: {node: '>=6.9.0'} @@ -512,12 +531,6 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-destructuring@7.28.0': - resolution: {integrity: sha512-v1nrSMBiKcodhsyJ4Gf+Z0U/yawmJDBOTpEB3mcQY52r9RIyPneGyAS/yM6seP/8I+mWI3elOMtT5dB8GJVs+A==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-destructuring@7.28.5': resolution: {integrity: sha512-Kl9Bc6D0zTUcFUvkNuQh4eGXPKKNDOJQXVyyM4ZAQPMveniJdxi8XMJwLo+xSoW3MIq81bD33lcUe9kZpl0MCw==} engines: {node: '>=6.9.0'} @@ -855,10 +868,6 @@ packages: resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==} engines: {node: '>=6.9.0'} - '@babel/traverse@7.28.4': - resolution: {integrity: sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ==} - engines: {node: '>=6.9.0'} - '@babel/traverse@7.28.5': resolution: {integrity: sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==} engines: {node: '>=6.9.0'} @@ -4636,12 +4645,10 @@ snapshots: '@babel/code-frame@7.27.1': dependencies: - '@babel/helper-validator-identifier': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 js-tokens: 4.0.0 picocolors: 1.1.1 - '@babel/compat-data@7.28.4': {} - '@babel/compat-data@7.28.5': {} '@babel/core@7.28.5': @@ -4664,14 +4671,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/generator@7.28.3': - dependencies: - '@babel/parser': 7.28.5 - '@babel/types': 7.28.5 - '@jridgewell/gen-mapping': 0.3.13 - '@jridgewell/trace-mapping': 0.3.31 - jsesc: 3.1.0 - '@babel/generator@7.28.5': dependencies: '@babel/parser': 7.28.5 @@ -4682,11 +4681,11 @@ snapshots: '@babel/helper-annotate-as-pure@7.27.3': dependencies: - '@babel/types': 7.28.4 + '@babel/types': 7.28.5 '@babel/helper-compilation-targets@7.27.2': dependencies: - '@babel/compat-data': 7.28.4 + '@babel/compat-data': 7.28.5 '@babel/helper-validator-option': 7.27.1 browserslist: 4.26.2 lru-cache: 5.1.1 @@ -4700,7 +4699,7 @@ snapshots: '@babel/helper-optimise-call-expression': 7.27.1 '@babel/helper-replace-supers': 7.27.1(@babel/core@7.28.5) '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 - '@babel/traverse': 7.28.4 + '@babel/traverse': 7.28.5 semver: 6.3.1 transitivePeerDependencies: - supports-color @@ -4749,15 +4748,15 @@ snapshots: '@babel/helper-member-expression-to-functions@7.27.1': dependencies: - '@babel/traverse': 7.28.4 - '@babel/types': 7.28.4 + '@babel/traverse': 7.28.5 + '@babel/types': 7.28.5 transitivePeerDependencies: - supports-color '@babel/helper-module-imports@7.27.1': dependencies: - '@babel/traverse': 7.28.4 - '@babel/types': 7.28.4 + '@babel/traverse': 7.28.5 + '@babel/types': 7.28.5 transitivePeerDependencies: - supports-color @@ -4765,14 +4764,14 @@ snapshots: dependencies: '@babel/core': 7.28.5 '@babel/helper-module-imports': 7.27.1 - '@babel/helper-validator-identifier': 7.27.1 - '@babel/traverse': 7.28.4 + '@babel/helper-validator-identifier': 7.28.5 + '@babel/traverse': 7.28.5 transitivePeerDependencies: - supports-color '@babel/helper-optimise-call-expression@7.27.1': dependencies: - '@babel/types': 7.28.4 + '@babel/types': 7.28.5 '@babel/helper-plugin-utils@7.27.1': {} @@ -4781,7 +4780,7 @@ snapshots: '@babel/core': 7.28.5 '@babel/helper-annotate-as-pure': 7.27.3 '@babel/helper-wrap-function': 7.28.3 - '@babel/traverse': 7.28.4 + '@babel/traverse': 7.28.5 transitivePeerDependencies: - supports-color @@ -4790,21 +4789,19 @@ snapshots: '@babel/core': 7.28.5 '@babel/helper-member-expression-to-functions': 7.27.1 '@babel/helper-optimise-call-expression': 7.27.1 - '@babel/traverse': 7.28.4 + '@babel/traverse': 7.28.5 transitivePeerDependencies: - supports-color '@babel/helper-skip-transparent-expression-wrappers@7.27.1': dependencies: - '@babel/traverse': 7.28.4 - '@babel/types': 7.28.4 + '@babel/traverse': 7.28.5 + '@babel/types': 7.28.5 transitivePeerDependencies: - supports-color '@babel/helper-string-parser@7.27.1': {} - '@babel/helper-validator-identifier@7.27.1': {} - '@babel/helper-validator-identifier@7.28.5': {} '@babel/helper-validator-option@7.27.1': {} @@ -4812,8 +4809,8 @@ snapshots: '@babel/helper-wrap-function@7.28.3': dependencies: '@babel/template': 7.27.2 - '@babel/traverse': 7.28.4 - '@babel/types': 7.28.4 + '@babel/traverse': 7.28.5 + '@babel/types': 7.28.5 transitivePeerDependencies: - supports-color @@ -4824,7 +4821,7 @@ snapshots: '@babel/parser@7.28.4': dependencies: - '@babel/types': 7.28.4 + '@babel/types': 7.28.5 '@babel/parser@7.28.5': dependencies: @@ -4861,7 +4858,7 @@ snapshots: dependencies: '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 - '@babel/traverse': 7.28.4 + '@babel/traverse': 7.28.5 transitivePeerDependencies: - supports-color @@ -4929,7 +4926,7 @@ snapshots: '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 '@babel/helper-remap-async-to-generator': 7.27.1(@babel/core@7.28.5) - '@babel/traverse': 7.28.4 + '@babel/traverse': 7.28.5 transitivePeerDependencies: - supports-color @@ -4976,7 +4973,7 @@ snapshots: '@babel/helper-globals': 7.28.0 '@babel/helper-plugin-utils': 7.27.1 '@babel/helper-replace-supers': 7.27.1(@babel/core@7.28.5) - '@babel/traverse': 7.28.4 + '@babel/traverse': 7.28.5 transitivePeerDependencies: - supports-color @@ -4986,14 +4983,6 @@ snapshots: '@babel/helper-plugin-utils': 7.27.1 '@babel/template': 7.27.2 - '@babel/plugin-transform-destructuring@7.28.0(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/traverse': 7.28.4 - transitivePeerDependencies: - - supports-color - '@babel/plugin-transform-destructuring@7.28.5(@babel/core@7.28.5)': dependencies: '@babel/core': 7.28.5 @@ -5066,7 +5055,7 @@ snapshots: '@babel/core': 7.28.5 '@babel/helper-compilation-targets': 7.27.2 '@babel/helper-plugin-utils': 7.27.1 - '@babel/traverse': 7.28.4 + '@babel/traverse': 7.28.5 transitivePeerDependencies: - supports-color @@ -5150,9 +5139,9 @@ snapshots: '@babel/core': 7.28.5 '@babel/helper-compilation-targets': 7.27.2 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-destructuring': 7.28.0(@babel/core@7.28.5) + '@babel/plugin-transform-destructuring': 7.28.5(@babel/core@7.28.5) '@babel/plugin-transform-parameters': 7.27.7(@babel/core@7.28.5) - '@babel/traverse': 7.28.4 + '@babel/traverse': 7.28.5 transitivePeerDependencies: - supports-color @@ -5233,7 +5222,7 @@ snapshots: '@babel/helper-module-imports': 7.27.1 '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.5) - '@babel/types': 7.28.4 + '@babel/types': 7.28.5 transitivePeerDependencies: - supports-color @@ -5409,7 +5398,7 @@ snapshots: dependencies: '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 - '@babel/types': 7.28.4 + '@babel/types': 7.28.5 esutils: 2.0.3 '@babel/preset-react@7.27.1(@babel/core@7.28.5)': @@ -5429,20 +5418,8 @@ snapshots: '@babel/template@7.27.2': dependencies: '@babel/code-frame': 7.27.1 - '@babel/parser': 7.28.4 - '@babel/types': 7.28.4 - - '@babel/traverse@7.28.4': - dependencies: - '@babel/code-frame': 7.27.1 - '@babel/generator': 7.28.3 - '@babel/helper-globals': 7.28.0 - '@babel/parser': 7.28.4 - '@babel/template': 7.27.2 - '@babel/types': 7.28.4 - debug: 4.4.3 - transitivePeerDependencies: - - supports-color + '@babel/parser': 7.28.5 + '@babel/types': 7.28.5 '@babel/traverse@7.28.5': dependencies: @@ -5459,7 +5436,7 @@ snapshots: '@babel/types@7.28.4': dependencies: '@babel/helper-string-parser': 7.27.1 - '@babel/helper-validator-identifier': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 '@babel/types@7.28.5': dependencies: @@ -6624,7 +6601,7 @@ snapshots: babel-plugin-polyfill-corejs2@0.4.14(@babel/core@7.28.5): dependencies: - '@babel/compat-data': 7.28.4 + '@babel/compat-data': 7.28.5 '@babel/core': 7.28.5 '@babel/helper-define-polyfill-provider': 0.6.5(@babel/core@7.28.5) semver: 6.3.1 diff --git a/rollup.config.js b/rollup.config.js index 8749d9dc9..55509b787 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -123,8 +123,6 @@ const bundleSizePlugin = (_options = {}) => { const BASE_CODE = "BASE_CODE"; // build the standalone distribution const STANDALONE = "STANDALONE"; -// build the standalone distribution, but put it in the sandbox directory -const SANDBOX = "SANDBOX"; // build the npm package entrypoint (createInstance) const NPM_PACKAGE_LOCAL = "NPM_PACKAGE_LOCAL"; // build from the published npm package @@ -133,8 +131,6 @@ const NPM_PACKAGE_PROD = "NPM_PACKAGE_PROD"; const CUSTOM_BUILD = "CUSTOM_BUILD"; // build the service worker (used for push notifications feature). const SERVICE_WORKER = "SERVICE_WORKER"; -// build the service worker (used for push notifications feature). -const SANDBOX_SERVICE_WORKER = "SANDBOX_SERVICE_WORKER"; // Add "_MIN" to the end of the option name to build the minified version const dirname = path.dirname(fileURLToPath(import.meta.url)); @@ -150,7 +146,7 @@ const buildPlugins = ({ variant, minify, babelPlugins }) => { commonjs(), ]; - if (variant !== SERVICE_WORKER && variant !== SANDBOX_SERVICE_WORKER) { + if (variant !== SERVICE_WORKER) { plugins.push( babel({ envName: "rollup", @@ -217,17 +213,12 @@ export const buildConfig = ({ const plugins = buildPlugins({ variant, minify, babelPlugins }); const minifiedExtension = minify ? ".min" : ""; - if (variant === SERVICE_WORKER || variant === SANDBOX_SERVICE_WORKER) { - const destDirectory = - variant === SANDBOX_SERVICE_WORKER - ? "sandboxes/browser/public/" - : "dist/"; + if (variant === SERVICE_WORKER) { return { input: `${dirname}/packages/core/src/serviceWorker.js`, output: [ { - file: - file || `${destDirectory}alloyServiceWorker${minifiedExtension}.js`, + file: file || `dist/alloyServiceWorker${minifiedExtension}.js`, format: "es", }, ], @@ -249,21 +240,13 @@ export const buildConfig = ({ }; } - if ( - variant === STANDALONE || - variant === SANDBOX || - variant === CUSTOM_BUILD - ) { - const destDirectory = - variant === SANDBOX ? "sandboxes/browser/public/" : "dist/"; - + if (variant === STANDALONE || variant === CUSTOM_BUILD) { return { input, output: [ { - file: file || `${destDirectory}alloy${minifiedExtension}.js`, + file: file || `dist/alloy${minifiedExtension}.js`, format: "iife", - sourcemap: variant === SANDBOX, }, ], plugins, @@ -299,10 +282,8 @@ const addConfig = (variant) => { addConfig(BASE_CODE); addConfig(STANDALONE); -addConfig(SANDBOX); addConfig(NPM_PACKAGE_LOCAL); addConfig(NPM_PACKAGE_PROD); addConfig(SERVICE_WORKER); -addConfig(SANDBOX_SERVICE_WORKER); export default config; From 5db6039820f6681b917dd2e61287ede09de53c43 Mon Sep 17 00:00:00 2001 From: Carter McBride <18412686+carterworks@users.noreply.github.com> Date: Thu, 30 Oct 2025 15:34:30 -0600 Subject: [PATCH 18/56] Migrate integration tests --- .../test/integration/helpers/advertising.js | 0 .../test/integration/helpers/alloy/clean.js | 0 .../test/integration/helpers/alloy/config.js | 0 .../test/integration/helpers/alloy/setup.js | 4 ++-- .../integration/helpers/alloy/setupBaseCode.js | 2 +- .../test/integration/helpers/constants/cookies.js | 0 .../test/integration/helpers/constants/domains.js | 0 .../contentCardsAndEventHistoryOperations.json | 0 .../integration/helpers/mocks/demdexResponse.json | 0 .../helpers/mocks/firstPartyAlloyResponse.json | 0 .../helpers/mocks/inAppMessageResponse.json | 0 .../helpers/mocks/sendEventErrorResponse.json | 0 .../helpers/mocks/sendEventResponse.json | 0 .../integration/helpers/mswjs/browserWorker.js | 0 .../test/integration/helpers/mswjs/handlers.js | 14 +++++++------- .../integration/helpers/mswjs/networkRecorder.js | 0 .../helpers/responses/createResponse.js | 2 +- .../test/integration/helpers/testsSetup/extend.js | 0 .../integration/helpers/utils/deleteCookies.js | 0 .../helpers/utils/getOnCommandResolvedPromise.js | 0 .../helpers/utils/searchForLogMessage.js | 0 .../test/integration/helpers/utils/waitFor.js | 0 .../AJO/content_cards_and_event_history.spec.js | 0 .../integration/specs/AJO/inapp_messages.spec.js | 0 .../specs/Advertising/clickthrough_both.spec.js | 0 .../specs/Advertising/clickthrough_efid.spec.js | 0 .../specs/Advertising/clickthrough_skwcid.spec.js | 0 .../specs/Advertising/options_modes.spec.js | 0 .../specs/Advertising/viewthrough_ids.spec.js | 0 .../integration/specs/Audiences/audiences.spec.js | 0 .../test/integration/specs/CNAME/cname.spec.js | 2 +- .../specs/Command Logic/commandQueueing.spec.js | 0 .../specs/Command Logic/configOverrides.spec.js | 0 .../specs/Command Logic/configureCommand.spec.js | 0 .../Command Logic/edgeConfigIdParameter.spec.js | 0 .../specs/Command Logic/sendEventCommand.spec.js | 0 .../specs/Command Logic/unknownCommand.spec.js | 0 .../Personalization/applyPropositions.spec.js | 0 vitest.config.js | 2 +- 39 files changed, 13 insertions(+), 13 deletions(-) rename packages/{core => browser}/test/integration/helpers/advertising.js (100%) rename packages/{core => browser}/test/integration/helpers/alloy/clean.js (100%) rename packages/{core => browser}/test/integration/helpers/alloy/config.js (100%) rename packages/{core => browser}/test/integration/helpers/alloy/setup.js (90%) rename packages/{core => browser}/test/integration/helpers/alloy/setupBaseCode.js (93%) rename packages/{core => browser}/test/integration/helpers/constants/cookies.js (100%) rename packages/{core => browser}/test/integration/helpers/constants/domains.js (100%) rename packages/{core => browser}/test/integration/helpers/mocks/contentCardsAndEventHistoryOperations.json (100%) rename packages/{core => browser}/test/integration/helpers/mocks/demdexResponse.json (100%) rename packages/{core => browser}/test/integration/helpers/mocks/firstPartyAlloyResponse.json (100%) rename packages/{core => browser}/test/integration/helpers/mocks/inAppMessageResponse.json (100%) rename packages/{core => browser}/test/integration/helpers/mocks/sendEventErrorResponse.json (100%) rename packages/{core => browser}/test/integration/helpers/mocks/sendEventResponse.json (100%) rename packages/{core => browser}/test/integration/helpers/mswjs/browserWorker.js (100%) rename packages/{core => browser}/test/integration/helpers/mswjs/handlers.js (83%) rename packages/{core => browser}/test/integration/helpers/mswjs/networkRecorder.js (100%) rename packages/{core => browser}/test/integration/helpers/responses/createResponse.js (88%) rename packages/{core => browser}/test/integration/helpers/testsSetup/extend.js (100%) rename packages/{core => browser}/test/integration/helpers/utils/deleteCookies.js (100%) rename packages/{core => browser}/test/integration/helpers/utils/getOnCommandResolvedPromise.js (100%) rename packages/{core => browser}/test/integration/helpers/utils/searchForLogMessage.js (100%) rename packages/{core => browser}/test/integration/helpers/utils/waitFor.js (100%) rename packages/{core => browser}/test/integration/specs/AJO/content_cards_and_event_history.spec.js (100%) rename packages/{core => browser}/test/integration/specs/AJO/inapp_messages.spec.js (100%) rename packages/{core => browser}/test/integration/specs/Advertising/clickthrough_both.spec.js (100%) rename packages/{core => browser}/test/integration/specs/Advertising/clickthrough_efid.spec.js (100%) rename packages/{core => browser}/test/integration/specs/Advertising/clickthrough_skwcid.spec.js (100%) rename packages/{core => browser}/test/integration/specs/Advertising/options_modes.spec.js (100%) rename packages/{core => browser}/test/integration/specs/Advertising/viewthrough_ids.spec.js (100%) rename packages/{core => browser}/test/integration/specs/Audiences/audiences.spec.js (100%) rename packages/{core => browser}/test/integration/specs/CNAME/cname.spec.js (95%) rename packages/{core => browser}/test/integration/specs/Command Logic/commandQueueing.spec.js (100%) rename packages/{core => browser}/test/integration/specs/Command Logic/configOverrides.spec.js (100%) rename packages/{core => browser}/test/integration/specs/Command Logic/configureCommand.spec.js (100%) rename packages/{core => browser}/test/integration/specs/Command Logic/edgeConfigIdParameter.spec.js (100%) rename packages/{core => browser}/test/integration/specs/Command Logic/sendEventCommand.spec.js (100%) rename packages/{core => browser}/test/integration/specs/Command Logic/unknownCommand.spec.js (100%) rename packages/{core => browser}/test/integration/specs/Personalization/applyPropositions.spec.js (100%) diff --git a/packages/core/test/integration/helpers/advertising.js b/packages/browser/test/integration/helpers/advertising.js similarity index 100% rename from packages/core/test/integration/helpers/advertising.js rename to packages/browser/test/integration/helpers/advertising.js diff --git a/packages/core/test/integration/helpers/alloy/clean.js b/packages/browser/test/integration/helpers/alloy/clean.js similarity index 100% rename from packages/core/test/integration/helpers/alloy/clean.js rename to packages/browser/test/integration/helpers/alloy/clean.js diff --git a/packages/core/test/integration/helpers/alloy/config.js b/packages/browser/test/integration/helpers/alloy/config.js similarity index 100% rename from packages/core/test/integration/helpers/alloy/config.js rename to packages/browser/test/integration/helpers/alloy/config.js diff --git a/packages/core/test/integration/helpers/alloy/setup.js b/packages/browser/test/integration/helpers/alloy/setup.js similarity index 90% rename from packages/core/test/integration/helpers/alloy/setup.js rename to packages/browser/test/integration/helpers/alloy/setup.js index b7565e8e0..5e3095da8 100644 --- a/packages/core/test/integration/helpers/alloy/setup.js +++ b/packages/browser/test/integration/helpers/alloy/setup.js @@ -15,7 +15,7 @@ const { readFile } = server.commands; export default async () => { const alloyBaseCode = await readFile( - `${server.config.root}/distTest/baseCode.min.js`, + `${server.config.root}/packages/browser/distTest/baseCode.min.js`, ); document.body.innerHTML = "Alloy Test Page"; @@ -28,7 +28,7 @@ export default async () => { const alloyScriptTag = document.createElement("script"); alloyScriptTag.type = "text/javascript"; alloyScriptTag.setAttribute("async", true); - alloyScriptTag.src = "/dist/alloy.js"; + alloyScriptTag.src = "/packages/browser/dist/alloy.js"; document.body.appendChild(alloyScriptTag); return window.alloy; diff --git a/packages/core/test/integration/helpers/alloy/setupBaseCode.js b/packages/browser/test/integration/helpers/alloy/setupBaseCode.js similarity index 93% rename from packages/core/test/integration/helpers/alloy/setupBaseCode.js rename to packages/browser/test/integration/helpers/alloy/setupBaseCode.js index 6efb27386..eb29b9d1c 100644 --- a/packages/core/test/integration/helpers/alloy/setupBaseCode.js +++ b/packages/browser/test/integration/helpers/alloy/setupBaseCode.js @@ -16,7 +16,7 @@ const { readFile } = server.commands; export default async () => { const alloyBaseCode = await readFile( - `${server.config.root}/distTest/baseCode.min.js`, + `${server.config.root}/packages/browser/distTest/baseCode.min.js`, ); document.body.innerHTML = "Alloy Test Page"; diff --git a/packages/core/test/integration/helpers/constants/cookies.js b/packages/browser/test/integration/helpers/constants/cookies.js similarity index 100% rename from packages/core/test/integration/helpers/constants/cookies.js rename to packages/browser/test/integration/helpers/constants/cookies.js diff --git a/packages/core/test/integration/helpers/constants/domains.js b/packages/browser/test/integration/helpers/constants/domains.js similarity index 100% rename from packages/core/test/integration/helpers/constants/domains.js rename to packages/browser/test/integration/helpers/constants/domains.js diff --git a/packages/core/test/integration/helpers/mocks/contentCardsAndEventHistoryOperations.json b/packages/browser/test/integration/helpers/mocks/contentCardsAndEventHistoryOperations.json similarity index 100% rename from packages/core/test/integration/helpers/mocks/contentCardsAndEventHistoryOperations.json rename to packages/browser/test/integration/helpers/mocks/contentCardsAndEventHistoryOperations.json diff --git a/packages/core/test/integration/helpers/mocks/demdexResponse.json b/packages/browser/test/integration/helpers/mocks/demdexResponse.json similarity index 100% rename from packages/core/test/integration/helpers/mocks/demdexResponse.json rename to packages/browser/test/integration/helpers/mocks/demdexResponse.json diff --git a/packages/core/test/integration/helpers/mocks/firstPartyAlloyResponse.json b/packages/browser/test/integration/helpers/mocks/firstPartyAlloyResponse.json similarity index 100% rename from packages/core/test/integration/helpers/mocks/firstPartyAlloyResponse.json rename to packages/browser/test/integration/helpers/mocks/firstPartyAlloyResponse.json diff --git a/packages/core/test/integration/helpers/mocks/inAppMessageResponse.json b/packages/browser/test/integration/helpers/mocks/inAppMessageResponse.json similarity index 100% rename from packages/core/test/integration/helpers/mocks/inAppMessageResponse.json rename to packages/browser/test/integration/helpers/mocks/inAppMessageResponse.json diff --git a/packages/core/test/integration/helpers/mocks/sendEventErrorResponse.json b/packages/browser/test/integration/helpers/mocks/sendEventErrorResponse.json similarity index 100% rename from packages/core/test/integration/helpers/mocks/sendEventErrorResponse.json rename to packages/browser/test/integration/helpers/mocks/sendEventErrorResponse.json diff --git a/packages/core/test/integration/helpers/mocks/sendEventResponse.json b/packages/browser/test/integration/helpers/mocks/sendEventResponse.json similarity index 100% rename from packages/core/test/integration/helpers/mocks/sendEventResponse.json rename to packages/browser/test/integration/helpers/mocks/sendEventResponse.json diff --git a/packages/core/test/integration/helpers/mswjs/browserWorker.js b/packages/browser/test/integration/helpers/mswjs/browserWorker.js similarity index 100% rename from packages/core/test/integration/helpers/mswjs/browserWorker.js rename to packages/browser/test/integration/helpers/mswjs/browserWorker.js diff --git a/packages/core/test/integration/helpers/mswjs/handlers.js b/packages/browser/test/integration/helpers/mswjs/handlers.js similarity index 83% rename from packages/core/test/integration/helpers/mswjs/handlers.js rename to packages/browser/test/integration/helpers/mswjs/handlers.js index b43c83bbc..1b3bb4d1c 100644 --- a/packages/core/test/integration/helpers/mswjs/handlers.js +++ b/packages/browser/test/integration/helpers/mswjs/handlers.js @@ -27,7 +27,7 @@ export const sendEventHandler = http.post( if (configId === "bc1a10e0-aee4-4e0e-ac5b-cdbb9abbec83") { return HttpResponse.text( await readFile( - `${server.config.root}/packages/core/test/integration/helpers/mocks/sendEventResponse.json`, + `${server.config.root}/packages/browser/test/integration/helpers/mocks/sendEventResponse.json`, ), ); } @@ -46,7 +46,7 @@ export const sendEventErrorHandler = http.post( if (configId === "BOGUS") { return HttpResponse.text( await readFile( - `${server.config.root}/packages/core/test/integration/helpers/mocks/sendEventErrorResponse.json`, + `${server.config.root}/packages/browser/test/integration/helpers/mocks/sendEventErrorResponse.json`, ), { status: 400, @@ -68,7 +68,7 @@ export const demdexHandler = http.post( if (configId === "bc1a10e0-aee4-4e0e-ac5b-cdbb9abbec83") { return HttpResponse.text( await readFile( - `${server.config.root}/packages/core/test/integration/helpers/mocks/demdexResponse.json`, + `${server.config.root}/packages/browser/test/integration/helpers/mocks/demdexResponse.json`, ), ); } @@ -87,7 +87,7 @@ export const firstPartyAlloyHandler = http.post( if (configId === "bc1a10e0-aee4-4e0e-ac5b-cdbb9abbec83") { return HttpResponse.text( await readFile( - `${server.config.root}/packages/core/test/integration/helpers/mocks/firstPartyAlloyResponse.json`, + `${server.config.root}/packages/browser/test/integration/helpers/mocks/firstPartyAlloyResponse.json`, ), ); } @@ -106,7 +106,7 @@ export const inAppMessageHandler = http.post( if (configId === "bc1a10e0-aee4-4e0e-ac5b-cdbb9abbec83") { return HttpResponse.text( await readFile( - `${server.config.root}/packages/core/test/integration/helpers/mocks/inAppMessageResponse.json`, + `${server.config.root}/packages/browser/test/integration/helpers/mocks/inAppMessageResponse.json`, ), ); } @@ -124,7 +124,7 @@ export const contentCardsAndEventHistoryOperationsOnSendEvent = http.post( if (configId === "bc1a10e0-aee4-4e0e-ac5b-cdbb9abbec83") { let response = await readFile( - `${server.config.root}/packages/core/test/integration/helpers/mocks/contentCardsAndEventHistoryOperations.json`, + `${server.config.root}/packages/browser/test/integration/helpers/mocks/contentCardsAndEventHistoryOperations.json`, ); response = response.replace( "{{value}}", @@ -147,7 +147,7 @@ export const contentCardsAndEventHistoryOperations = http.post( if (configId === "bc1a10e0-aee4-4e0e-ac5b-cdbb9abbec83") { let response = await readFile( - `${server.config.root}/packages/core/test/integration/helpers/mocks/contentCardsAndEventHistoryOperations.json`, + `${server.config.root}/packages/browser/test/integration/helpers/mocks/contentCardsAndEventHistoryOperations.json`, ); response = response.replace("{{value}}", "someOtherValue"); diff --git a/packages/core/test/integration/helpers/mswjs/networkRecorder.js b/packages/browser/test/integration/helpers/mswjs/networkRecorder.js similarity index 100% rename from packages/core/test/integration/helpers/mswjs/networkRecorder.js rename to packages/browser/test/integration/helpers/mswjs/networkRecorder.js diff --git a/packages/core/test/integration/helpers/responses/createResponse.js b/packages/browser/test/integration/helpers/responses/createResponse.js similarity index 88% rename from packages/core/test/integration/helpers/responses/createResponse.js rename to packages/browser/test/integration/helpers/responses/createResponse.js index c41e8887a..8c633517c 100644 --- a/packages/core/test/integration/helpers/responses/createResponse.js +++ b/packages/browser/test/integration/helpers/responses/createResponse.js @@ -10,6 +10,6 @@ OF ANY KIND, either express or implied. See the License for the specific languag governing permissions and limitations under the License. */ -import injectCreateResponse from "../../../../src/core/injectCreateResponse.js"; +import injectCreateResponse from "../../../../../core/src/core/injectCreateResponse.js"; export default injectCreateResponse({ logger: console }); diff --git a/packages/core/test/integration/helpers/testsSetup/extend.js b/packages/browser/test/integration/helpers/testsSetup/extend.js similarity index 100% rename from packages/core/test/integration/helpers/testsSetup/extend.js rename to packages/browser/test/integration/helpers/testsSetup/extend.js diff --git a/packages/core/test/integration/helpers/utils/deleteCookies.js b/packages/browser/test/integration/helpers/utils/deleteCookies.js similarity index 100% rename from packages/core/test/integration/helpers/utils/deleteCookies.js rename to packages/browser/test/integration/helpers/utils/deleteCookies.js diff --git a/packages/core/test/integration/helpers/utils/getOnCommandResolvedPromise.js b/packages/browser/test/integration/helpers/utils/getOnCommandResolvedPromise.js similarity index 100% rename from packages/core/test/integration/helpers/utils/getOnCommandResolvedPromise.js rename to packages/browser/test/integration/helpers/utils/getOnCommandResolvedPromise.js diff --git a/packages/core/test/integration/helpers/utils/searchForLogMessage.js b/packages/browser/test/integration/helpers/utils/searchForLogMessage.js similarity index 100% rename from packages/core/test/integration/helpers/utils/searchForLogMessage.js rename to packages/browser/test/integration/helpers/utils/searchForLogMessage.js diff --git a/packages/core/test/integration/helpers/utils/waitFor.js b/packages/browser/test/integration/helpers/utils/waitFor.js similarity index 100% rename from packages/core/test/integration/helpers/utils/waitFor.js rename to packages/browser/test/integration/helpers/utils/waitFor.js diff --git a/packages/core/test/integration/specs/AJO/content_cards_and_event_history.spec.js b/packages/browser/test/integration/specs/AJO/content_cards_and_event_history.spec.js similarity index 100% rename from packages/core/test/integration/specs/AJO/content_cards_and_event_history.spec.js rename to packages/browser/test/integration/specs/AJO/content_cards_and_event_history.spec.js diff --git a/packages/core/test/integration/specs/AJO/inapp_messages.spec.js b/packages/browser/test/integration/specs/AJO/inapp_messages.spec.js similarity index 100% rename from packages/core/test/integration/specs/AJO/inapp_messages.spec.js rename to packages/browser/test/integration/specs/AJO/inapp_messages.spec.js diff --git a/packages/core/test/integration/specs/Advertising/clickthrough_both.spec.js b/packages/browser/test/integration/specs/Advertising/clickthrough_both.spec.js similarity index 100% rename from packages/core/test/integration/specs/Advertising/clickthrough_both.spec.js rename to packages/browser/test/integration/specs/Advertising/clickthrough_both.spec.js diff --git a/packages/core/test/integration/specs/Advertising/clickthrough_efid.spec.js b/packages/browser/test/integration/specs/Advertising/clickthrough_efid.spec.js similarity index 100% rename from packages/core/test/integration/specs/Advertising/clickthrough_efid.spec.js rename to packages/browser/test/integration/specs/Advertising/clickthrough_efid.spec.js diff --git a/packages/core/test/integration/specs/Advertising/clickthrough_skwcid.spec.js b/packages/browser/test/integration/specs/Advertising/clickthrough_skwcid.spec.js similarity index 100% rename from packages/core/test/integration/specs/Advertising/clickthrough_skwcid.spec.js rename to packages/browser/test/integration/specs/Advertising/clickthrough_skwcid.spec.js diff --git a/packages/core/test/integration/specs/Advertising/options_modes.spec.js b/packages/browser/test/integration/specs/Advertising/options_modes.spec.js similarity index 100% rename from packages/core/test/integration/specs/Advertising/options_modes.spec.js rename to packages/browser/test/integration/specs/Advertising/options_modes.spec.js diff --git a/packages/core/test/integration/specs/Advertising/viewthrough_ids.spec.js b/packages/browser/test/integration/specs/Advertising/viewthrough_ids.spec.js similarity index 100% rename from packages/core/test/integration/specs/Advertising/viewthrough_ids.spec.js rename to packages/browser/test/integration/specs/Advertising/viewthrough_ids.spec.js diff --git a/packages/core/test/integration/specs/Audiences/audiences.spec.js b/packages/browser/test/integration/specs/Audiences/audiences.spec.js similarity index 100% rename from packages/core/test/integration/specs/Audiences/audiences.spec.js rename to packages/browser/test/integration/specs/Audiences/audiences.spec.js diff --git a/packages/core/test/integration/specs/CNAME/cname.spec.js b/packages/browser/test/integration/specs/CNAME/cname.spec.js similarity index 95% rename from packages/core/test/integration/specs/CNAME/cname.spec.js rename to packages/browser/test/integration/specs/CNAME/cname.spec.js index 23c41559f..f4f9fbd45 100644 --- a/packages/core/test/integration/specs/CNAME/cname.spec.js +++ b/packages/browser/test/integration/specs/CNAME/cname.spec.js @@ -14,7 +14,7 @@ import { describe, test, expect } from "../../helpers/testsSetup/extend.js"; import deleteCookies from "../../helpers/utils/deleteCookies.js"; import createResponse from "../../helpers/responses/createResponse.js"; import { FIRST_PARTY_DOMAIN } from "../../helpers/constants/domains.js"; -import { MAIN_IDENTITY_COOKIE_NAME } from "../../../functional/helpers/constants/cookies.js"; +import { MAIN_IDENTITY_COOKIE_NAME } from "../../helpers/constants/cookies.js"; import { demdexHandler, firstPartyAlloyHandler, diff --git a/packages/core/test/integration/specs/Command Logic/commandQueueing.spec.js b/packages/browser/test/integration/specs/Command Logic/commandQueueing.spec.js similarity index 100% rename from packages/core/test/integration/specs/Command Logic/commandQueueing.spec.js rename to packages/browser/test/integration/specs/Command Logic/commandQueueing.spec.js diff --git a/packages/core/test/integration/specs/Command Logic/configOverrides.spec.js b/packages/browser/test/integration/specs/Command Logic/configOverrides.spec.js similarity index 100% rename from packages/core/test/integration/specs/Command Logic/configOverrides.spec.js rename to packages/browser/test/integration/specs/Command Logic/configOverrides.spec.js diff --git a/packages/core/test/integration/specs/Command Logic/configureCommand.spec.js b/packages/browser/test/integration/specs/Command Logic/configureCommand.spec.js similarity index 100% rename from packages/core/test/integration/specs/Command Logic/configureCommand.spec.js rename to packages/browser/test/integration/specs/Command Logic/configureCommand.spec.js diff --git a/packages/core/test/integration/specs/Command Logic/edgeConfigIdParameter.spec.js b/packages/browser/test/integration/specs/Command Logic/edgeConfigIdParameter.spec.js similarity index 100% rename from packages/core/test/integration/specs/Command Logic/edgeConfigIdParameter.spec.js rename to packages/browser/test/integration/specs/Command Logic/edgeConfigIdParameter.spec.js diff --git a/packages/core/test/integration/specs/Command Logic/sendEventCommand.spec.js b/packages/browser/test/integration/specs/Command Logic/sendEventCommand.spec.js similarity index 100% rename from packages/core/test/integration/specs/Command Logic/sendEventCommand.spec.js rename to packages/browser/test/integration/specs/Command Logic/sendEventCommand.spec.js diff --git a/packages/core/test/integration/specs/Command Logic/unknownCommand.spec.js b/packages/browser/test/integration/specs/Command Logic/unknownCommand.spec.js similarity index 100% rename from packages/core/test/integration/specs/Command Logic/unknownCommand.spec.js rename to packages/browser/test/integration/specs/Command Logic/unknownCommand.spec.js diff --git a/packages/core/test/integration/specs/Personalization/applyPropositions.spec.js b/packages/browser/test/integration/specs/Personalization/applyPropositions.spec.js similarity index 100% rename from packages/core/test/integration/specs/Personalization/applyPropositions.spec.js rename to packages/browser/test/integration/specs/Personalization/applyPropositions.spec.js diff --git a/vitest.config.js b/vitest.config.js index fe10c2619..b6c5b9672 100644 --- a/vitest.config.js +++ b/vitest.config.js @@ -44,7 +44,7 @@ export default defineConfig({ test: { name: "integration", include: [ - "packages/core/test/integration/**/*.{test,spec}.?(c|m)[jt]s?(x)", + "packages/*/test/integration/**/*.{test,spec}.?(c|m)[jt]s?(x)", ], isolate: false, browser: { From 08fc3dbc6196941450cbb497c3a0642064a3d736 Mon Sep 17 00:00:00 2001 From: Carter McBride <18412686+carterworks@users.noreply.github.com> Date: Thu, 30 Oct 2025 16:08:33 -0600 Subject: [PATCH 19/56] Move functional tests into browser package --- .testcaferc.json | 5 - package.json | 8 +- packages/browser/.testcaferc.json | 6 + packages/browser/package.json | 8 +- .../browser/scripts}/runFunctionalTests.js | 9 +- .../browser/scripts}/watchFunctionalTests.js | 0 .../fixtures/Personalization/C28758.js | 57 ++ .../fixtures/Personalization/C6364800.js | 80 ++ .../fixtures/Personalization/C9932846.js | 25 + .../Personalization/conflictResolution.js | 251 +++++++ .../helpers/areThirdPartyCookiesSupported.js | 30 + .../helpers/assertions/advertising.js | 217 ++++++ .../functional/helpers/assertions/index.js | 13 + .../helpers/assertions/responseStatus.js | 32 + .../helpers/configureAlloyInstance/index.js | 27 + .../functional/helpers/consoleLogger/index.js | 147 ++++ .../helpers/constants/alloyEnvironment.js | 14 + .../functional/helpers/constants/browsers.js | 19 + .../configParts/ajoConfigForStage.js | 17 + .../configParts/clickCollectionDisabled.js | 14 + .../configParts/clickCollectionEnabled.js | 14 + .../clickCollectionEventGroupingDisabled.js | 16 + .../clickCollectionSessionStorageDisabled.js | 16 + .../configParts/configOverridesAlt.js | 29 + .../configParts/configOverridesMain.js | 29 + .../constants/configParts/consentIn.js | 14 + .../constants/configParts/consentPending.js | 14 + .../constants/configParts/debugDisabled.js | 14 + .../constants/configParts/debugEnabled.js | 14 + .../configParts/edgeDomainFirstParty.js | 16 + .../configParts/edgeDomainThirdParty.js | 16 + .../helpers/constants/configParts/index.js | 57 ++ .../configParts/migrationDisabled.js | 14 + .../constants/configParts/migrationEnabled.js | 14 + .../constants/configParts/orgAltConfigAlt.js | 16 + .../configParts/orgMainConfigMain.js | 14 + .../constants/configParts/orgMediaConfig.js | 17 + .../constants/configParts/streamingMedia.js | 17 + .../configParts/targetMigrationEnabled.js | 14 + .../configParts/thirdPartyCookiesDisabled.js | 15 + .../configParts/thirdPartyCookiesEnabled.js | 15 + .../functional/helpers/constants/consent.js | 145 ++++ .../functional/helpers/constants/cookies.js | 21 + .../helpers/constants/datastreamId.js | 12 + .../helpers/constants/deviceContextConfig.js | 17 + .../functional/helpers/constants/domain.js | 14 + .../constants/environmentContextConfig.js | 17 + .../highEntropyUserAgentHintsContextConfig.js | 17 + .../helpers/constants/placeContextConfig.js | 17 + .../functional/helpers/constants/regex.js | 13 + .../constants/remoteVisitorLibraryUrl.js | 13 + .../test/functional/helpers/constants/url.js | 24 + .../helpers/constants/webContextConfig.js | 17 + .../test/functional/helpers/cookies.js | 57 ++ .../test/functional/helpers/createAdobeMC.js | 22 + .../functional/helpers/createAlloyProxy.js | 124 +++ .../helpers/createCollectEndpointAsserter.js | 120 +++ .../helpers/createFixture/clientScripts.js | 223 ++++++ .../createFixture/destinationRequestMock.js | 23 + .../functional/helpers/createFixture/index.js | 35 + .../functional/helpers/createRandomEcid.js | 24 + .../test/functional/helpers/createResponse.js | 15 + .../helpers/createUnhandledRejectionLogger.js | 83 ++ .../functional/helpers/dom/addHtmlToBody.js | 25 + .../functional/helpers/dom/addHtmlToHeader.js | 20 + .../functional/helpers/flushPromiseChains.js | 32 + .../test/functional/helpers/getBaseConfig.js | 30 + .../isUserAgentClientHintsSupported.js | 15 + .../networkLogger/awaitRequestResponse.js | 21 + .../helpers/networkLogger/getResponseBody.js | 38 + .../helpers/networkLogger/getReturnedEcid.js | 26 + .../functional/helpers/networkLogger/index.js | 148 ++++ .../helpers/optIn/createMockOptIn.js | 31 + .../helpers/preventLinkNavigation.js | 24 + .../test/functional/helpers/reloadPage.js | 56 ++ .../helpers/requestHooks/demdexBlockerMock.js | 23 + .../helpers/requestHooks/failOnceHook.js | 41 + .../helpers/requestHooks/sequentialHook.js | 47 ++ .../test/functional/helpers/sendBeaconMock.js | 48 ++ .../helpers/setLegacyIdentityCookie.js | 24 + .../helpers/visitorService/getVisitorEcid.js | 22 + .../test/functional/specs/Audiences/C12411.js | 56 ++ .../test/functional/specs/Audiences/C12412.js | 74 ++ .../test/functional/specs/Audiences/C31436.js | 57 ++ .../test/functional/specs/CNAME/C148846.js | 101 +++ .../specs/Command Logic/C11634155.js | 73 ++ .../functional/specs/Command Logic/C13816.js | 35 + .../functional/specs/Command Logic/C13817.js | 30 + .../functional/specs/Command Logic/C13818.js | 63 ++ .../functional/specs/Command Logic/C13819.js | 47 ++ .../functional/specs/Command Logic/C2580.js | 48 ++ .../functional/specs/Command Logic/C2585.js | 35 + .../functional/specs/Command Logic/C2587.js | 48 ++ .../functional/specs/Command Logic/C2588.js | 36 + .../specs/Command Logic/C3484892.js | 33 + .../specs/Config Overrides/C7437530.js | 239 ++++++ .../specs/Config Overrides/C7437531.js | 184 +++++ .../specs/Config Overrides/C7437532.js | 192 +++++ .../specs/Config Overrides/C7437533.js | 200 +++++ .../test/functional/specs/Consent/C14404.js | 64 ++ .../test/functional/specs/Consent/C14405.js | 50 ++ .../test/functional/specs/Consent/C14406.js | 48 ++ .../test/functional/specs/Consent/C14407.js | 48 ++ .../test/functional/specs/Consent/C14409.js | 55 ++ .../test/functional/specs/Consent/C14410.js | 72 ++ .../test/functional/specs/Consent/C14411.js | 55 ++ .../test/functional/specs/Consent/C14414.js | 68 ++ .../test/functional/specs/Consent/C1472433.js | 59 ++ .../test/functional/specs/Consent/C1472434.js | 59 ++ .../test/functional/specs/Consent/C1472435.js | 73 ++ .../test/functional/specs/Consent/C1472436.js | 70 ++ .../test/functional/specs/Consent/C1472437.js | 58 ++ .../test/functional/specs/Consent/C1472438.js | 58 ++ .../test/functional/specs/Consent/C1576777.js | 70 ++ .../test/functional/specs/Consent/C1631712.js | 60 ++ .../test/functional/specs/Consent/C225953.js | 54 ++ .../test/functional/specs/Consent/C25148.js | 60 ++ .../test/functional/specs/Consent/C2593.js | 52 ++ .../test/functional/specs/Consent/C2594.js | 53 ++ .../test/functional/specs/Consent/C2660.js | 70 ++ .../test/functional/specs/Consent/C28754.js | 68 ++ .../test/functional/specs/Consent/C5594870.js | 61 ++ .../functional/specs/Consent/IAB/C224670.js | 74 ++ .../functional/specs/Consent/IAB/C224671.js | 79 ++ .../functional/specs/Consent/IAB/C224672.js | 75 ++ .../functional/specs/Consent/IAB/C224673.js | 74 ++ .../functional/specs/Consent/IAB/C224674.js | 74 ++ .../functional/specs/Consent/IAB/C224675.js | 124 +++ .../functional/specs/Consent/IAB/C224676.js | 83 ++ .../functional/specs/Consent/IAB/C224677.js | 91 +++ .../functional/specs/Consent/IAB/C224678.js | 111 +++ .../test/functional/specs/Context/C1911390.js | 104 +++ .../test/functional/specs/Context/C2597.js | 60 ++ .../test/functional/specs/Context/C2598.js | 77 ++ .../test/functional/specs/Context/C2599.js | 71 ++ .../test/functional/specs/Context/C2600.js | 71 ++ .../test/functional/specs/Context/C2601.js | 71 ++ .../test/functional/specs/Context/C7311732.js | 71 ++ .../specs/Data Collector/C11693274.js | 69 ++ .../specs/Data Collector/C1715149.js | 100 +++ .../specs/Data Collector/C225010.js | 61 ++ .../functional/specs/Data Collector/C2592.js | 63 ++ .../specs/Data Collector/C455258.js | 49 ++ .../functional/specs/Data Collector/C75372.js | 57 ++ .../functional/specs/Data Collector/C8118.js | 503 +++++++++++++ .../functional/specs/Data Collector/C81181.js | 330 ++++++++ .../functional/specs/Data Collector/C81182.js | 165 ++++ .../functional/specs/Data Collector/C81183.js | 146 ++++ .../functional/specs/Data Collector/C81184.js | 146 ++++ .../functional/specs/Data Collector/C8119.js | 55 ++ .../specs/Data Collector/C9369211.js | 70 ++ .../functional/specs/ID Migration/C14394.js | 73 ++ .../functional/specs/ID Migration/C14399.js | 83 ++ .../functional/specs/ID Migration/C14400.js | 84 +++ .../functional/specs/ID Migration/C14401.js | 71 ++ .../functional/specs/ID Migration/C14402.js | 93 +++ .../functional/specs/ID Migration/C14403.js | 73 ++ .../functional/specs/ID Migration/C5752639.js | 73 ++ .../test/functional/specs/Identity/C10922.js | 157 ++++ .../functional/specs/Identity/C14699834.js | 119 +++ .../functional/specs/Identity/C15325238.js | 75 ++ .../functional/specs/Identity/C1703722.js | 50 ++ .../functional/specs/Identity/C1703723.js | 52 ++ .../functional/specs/Identity/C19160486.js | 176 +++++ .../functional/specs/Identity/C21636436.js | 72 ++ .../functional/specs/Identity/C21636437.js | 60 ++ .../functional/specs/Identity/C21636438.js | 118 +++ .../test/functional/specs/Identity/C2581.js | 57 ++ .../test/functional/specs/Identity/C25822.js | 92 +++ .../functional/specs/Identity/C5287654.js | 81 ++ .../functional/specs/Identity/C5594865.js | 66 ++ .../functional/specs/Identity/C5594866.js | 79 ++ .../functional/specs/Identity/C5594871.js | 47 ++ .../functional/specs/Identity/C5594872.js | 54 ++ .../functional/specs/Identity/C5598188.js | 46 ++ .../functional/specs/Identity/C6842980.js | 77 ++ .../functional/specs/Identity/C6842981.js | 90 +++ .../functional/specs/Identity/C6842982.js | 72 ++ .../functional/specs/Install SDK/C1338399.js | 52 ++ .../functional/specs/Install SDK/C2560.js | 30 + .../functional/specs/Install SDK/C2579.js | 85 +++ .../functional/specs/LibraryInfo/C2589.js | 125 +++ .../specs/Location Hints/C6589015.js | 61 ++ .../specs/Location Hints/C6944931.js | 65 ++ .../test/functional/specs/Logging/C2583.js | 57 ++ .../test/functional/specs/Logging/C2584.js | 42 ++ .../test/functional/specs/Logging/C2586.js | 35 + .../test/functional/specs/Logging/C532204.js | 58 ++ .../functional/specs/MediaCollection/MA1.js | 302 ++++++++ .../functional/specs/MediaCollection/MA2.js | 384 ++++++++++ .../functional/specs/MediaCollection/MA3.js | 286 +++++++ .../functional/specs/Migration/C8085773.js | 104 +++ .../functional/specs/Migration/C8085774.js | 103 +++ .../functional/specs/Migration/C8085775.js | 102 +++ .../functional/specs/Migration/C8085776.js | 102 +++ .../functional/specs/Migration/C8085777.js | 133 ++++ .../functional/specs/Migration/C8085778.js | 120 +++ .../functional/specs/Migration/C8085779.js | 108 +++ .../functional/specs/Migration/C8085780.js | 104 +++ .../test/functional/specs/Migration/helper.js | 113 +++ .../specs/Personalization/C11389844.js | 191 +++++ .../specs/Personalization/C1234567.js | 711 ++++++++++++++++++ .../specs/Personalization/C14286730.js | 90 +++ .../specs/Personalization/C14299419.js | 47 ++ .../specs/Personalization/C14299420.js | 46 ++ .../specs/Personalization/C14299421.js | 61 ++ .../specs/Personalization/C14299422.js | 47 ++ .../specs/Personalization/C14317242.js | 148 ++++ .../specs/Personalization/C15325239.js | 62 ++ .../specs/Personalization/C17294899.js | 61 ++ .../specs/Personalization/C17409728.js | 427 +++++++++++ .../specs/Personalization/C205528.js | 86 +++ .../specs/Personalization/C205529.js | 82 ++ .../specs/Personalization/C21636439.js | 133 ++++ .../specs/Personalization/C21886916.js | 86 +++ .../specs/Personalization/C22098199.js | 210 ++++++ .../specs/Personalization/C28755.js | 105 +++ .../specs/Personalization/C28756.js | 79 ++ .../specs/Personalization/C28757.js | 101 +++ .../specs/Personalization/C28758.js | 132 ++++ .../specs/Personalization/C28759.js | 114 +++ .../specs/Personalization/C28760.js | 126 ++++ .../specs/Personalization/C3272624.js | 99 +++ .../specs/Personalization/C44363.js | 72 ++ .../specs/Personalization/C5298194.js | 64 ++ .../specs/Personalization/C5805675.js | 145 ++++ .../specs/Personalization/C5805676.js | 120 +++ .../specs/Personalization/C6364797.js | 131 ++++ .../specs/Personalization/C6364798.js | 293 ++++++++ .../specs/Personalization/C6364799.js | 121 +++ .../specs/Personalization/C6364800.js | 239 ++++++ .../specs/Personalization/C6984408.js | 70 ++ .../specs/Personalization/C7494472.js | 126 ++++ .../specs/Personalization/C7498683.js | 63 ++ .../specs/Personalization/C753469.js | 56 ++ .../specs/Personalization/C753470.js | 53 ++ .../specs/Personalization/C7638574.js | 103 +++ .../specs/Personalization/C782718.js | 264 +++++++ .../specs/Personalization/C782719.js | 153 ++++ .../specs/Personalization/C7878996.js | 113 +++ .../specs/Personalization/C8631576.js | 82 ++ .../specs/Personalization/C8631577.js | 109 +++ .../specs/Personalization/C9932846.js | 138 ++++ .../functional/specs/RulesEngine/C13348429.js | 88 +++ .../functional/specs/RulesEngine/C13405889.js | 92 +++ .../functional/specs/RulesEngine/C13419240.js | 62 ++ .../test/functional/specs/Visitor/C35448.js | 59 ++ .../test/functional/specs/Visitor/C35450.js | 56 ++ .../test/functional/specs/Visitor/C36908.js | 57 ++ .../test/functional/specs/Visitor/C36909.js | 53 ++ 250 files changed, 20123 insertions(+), 12 deletions(-) delete mode 100644 .testcaferc.json create mode 100644 packages/browser/.testcaferc.json rename {scripts/helpers => packages/browser/scripts}/runFunctionalTests.js (86%) rename {scripts => packages/browser/scripts}/watchFunctionalTests.js (100%) create mode 100644 packages/browser/test/functional/fixtures/Personalization/C28758.js create mode 100644 packages/browser/test/functional/fixtures/Personalization/C6364800.js create mode 100644 packages/browser/test/functional/fixtures/Personalization/C9932846.js create mode 100644 packages/browser/test/functional/fixtures/Personalization/conflictResolution.js create mode 100644 packages/browser/test/functional/helpers/areThirdPartyCookiesSupported.js create mode 100644 packages/browser/test/functional/helpers/assertions/advertising.js create mode 100644 packages/browser/test/functional/helpers/assertions/index.js create mode 100644 packages/browser/test/functional/helpers/assertions/responseStatus.js create mode 100644 packages/browser/test/functional/helpers/configureAlloyInstance/index.js create mode 100644 packages/browser/test/functional/helpers/consoleLogger/index.js create mode 100644 packages/browser/test/functional/helpers/constants/alloyEnvironment.js create mode 100644 packages/browser/test/functional/helpers/constants/browsers.js create mode 100644 packages/browser/test/functional/helpers/constants/configParts/ajoConfigForStage.js create mode 100644 packages/browser/test/functional/helpers/constants/configParts/clickCollectionDisabled.js create mode 100644 packages/browser/test/functional/helpers/constants/configParts/clickCollectionEnabled.js create mode 100644 packages/browser/test/functional/helpers/constants/configParts/clickCollectionEventGroupingDisabled.js create mode 100644 packages/browser/test/functional/helpers/constants/configParts/clickCollectionSessionStorageDisabled.js create mode 100644 packages/browser/test/functional/helpers/constants/configParts/configOverridesAlt.js create mode 100644 packages/browser/test/functional/helpers/constants/configParts/configOverridesMain.js create mode 100644 packages/browser/test/functional/helpers/constants/configParts/consentIn.js create mode 100644 packages/browser/test/functional/helpers/constants/configParts/consentPending.js create mode 100644 packages/browser/test/functional/helpers/constants/configParts/debugDisabled.js create mode 100644 packages/browser/test/functional/helpers/constants/configParts/debugEnabled.js create mode 100644 packages/browser/test/functional/helpers/constants/configParts/edgeDomainFirstParty.js create mode 100644 packages/browser/test/functional/helpers/constants/configParts/edgeDomainThirdParty.js create mode 100644 packages/browser/test/functional/helpers/constants/configParts/index.js create mode 100644 packages/browser/test/functional/helpers/constants/configParts/migrationDisabled.js create mode 100644 packages/browser/test/functional/helpers/constants/configParts/migrationEnabled.js create mode 100644 packages/browser/test/functional/helpers/constants/configParts/orgAltConfigAlt.js create mode 100644 packages/browser/test/functional/helpers/constants/configParts/orgMainConfigMain.js create mode 100644 packages/browser/test/functional/helpers/constants/configParts/orgMediaConfig.js create mode 100644 packages/browser/test/functional/helpers/constants/configParts/streamingMedia.js create mode 100644 packages/browser/test/functional/helpers/constants/configParts/targetMigrationEnabled.js create mode 100644 packages/browser/test/functional/helpers/constants/configParts/thirdPartyCookiesDisabled.js create mode 100644 packages/browser/test/functional/helpers/constants/configParts/thirdPartyCookiesEnabled.js create mode 100644 packages/browser/test/functional/helpers/constants/consent.js create mode 100644 packages/browser/test/functional/helpers/constants/cookies.js create mode 100644 packages/browser/test/functional/helpers/constants/datastreamId.js create mode 100644 packages/browser/test/functional/helpers/constants/deviceContextConfig.js create mode 100644 packages/browser/test/functional/helpers/constants/domain.js create mode 100644 packages/browser/test/functional/helpers/constants/environmentContextConfig.js create mode 100644 packages/browser/test/functional/helpers/constants/highEntropyUserAgentHintsContextConfig.js create mode 100644 packages/browser/test/functional/helpers/constants/placeContextConfig.js create mode 100644 packages/browser/test/functional/helpers/constants/regex.js create mode 100644 packages/browser/test/functional/helpers/constants/remoteVisitorLibraryUrl.js create mode 100644 packages/browser/test/functional/helpers/constants/url.js create mode 100644 packages/browser/test/functional/helpers/constants/webContextConfig.js create mode 100644 packages/browser/test/functional/helpers/cookies.js create mode 100644 packages/browser/test/functional/helpers/createAdobeMC.js create mode 100644 packages/browser/test/functional/helpers/createAlloyProxy.js create mode 100644 packages/browser/test/functional/helpers/createCollectEndpointAsserter.js create mode 100644 packages/browser/test/functional/helpers/createFixture/clientScripts.js create mode 100644 packages/browser/test/functional/helpers/createFixture/destinationRequestMock.js create mode 100644 packages/browser/test/functional/helpers/createFixture/index.js create mode 100644 packages/browser/test/functional/helpers/createRandomEcid.js create mode 100644 packages/browser/test/functional/helpers/createResponse.js create mode 100644 packages/browser/test/functional/helpers/createUnhandledRejectionLogger.js create mode 100644 packages/browser/test/functional/helpers/dom/addHtmlToBody.js create mode 100644 packages/browser/test/functional/helpers/dom/addHtmlToHeader.js create mode 100644 packages/browser/test/functional/helpers/flushPromiseChains.js create mode 100644 packages/browser/test/functional/helpers/getBaseConfig.js create mode 100644 packages/browser/test/functional/helpers/isUserAgentClientHintsSupported.js create mode 100644 packages/browser/test/functional/helpers/networkLogger/awaitRequestResponse.js create mode 100644 packages/browser/test/functional/helpers/networkLogger/getResponseBody.js create mode 100644 packages/browser/test/functional/helpers/networkLogger/getReturnedEcid.js create mode 100644 packages/browser/test/functional/helpers/networkLogger/index.js create mode 100644 packages/browser/test/functional/helpers/optIn/createMockOptIn.js create mode 100644 packages/browser/test/functional/helpers/preventLinkNavigation.js create mode 100644 packages/browser/test/functional/helpers/reloadPage.js create mode 100644 packages/browser/test/functional/helpers/requestHooks/demdexBlockerMock.js create mode 100644 packages/browser/test/functional/helpers/requestHooks/failOnceHook.js create mode 100644 packages/browser/test/functional/helpers/requestHooks/sequentialHook.js create mode 100644 packages/browser/test/functional/helpers/sendBeaconMock.js create mode 100644 packages/browser/test/functional/helpers/setLegacyIdentityCookie.js create mode 100644 packages/browser/test/functional/helpers/visitorService/getVisitorEcid.js create mode 100644 packages/browser/test/functional/specs/Audiences/C12411.js create mode 100644 packages/browser/test/functional/specs/Audiences/C12412.js create mode 100644 packages/browser/test/functional/specs/Audiences/C31436.js create mode 100644 packages/browser/test/functional/specs/CNAME/C148846.js create mode 100644 packages/browser/test/functional/specs/Command Logic/C11634155.js create mode 100644 packages/browser/test/functional/specs/Command Logic/C13816.js create mode 100644 packages/browser/test/functional/specs/Command Logic/C13817.js create mode 100644 packages/browser/test/functional/specs/Command Logic/C13818.js create mode 100644 packages/browser/test/functional/specs/Command Logic/C13819.js create mode 100644 packages/browser/test/functional/specs/Command Logic/C2580.js create mode 100644 packages/browser/test/functional/specs/Command Logic/C2585.js create mode 100644 packages/browser/test/functional/specs/Command Logic/C2587.js create mode 100644 packages/browser/test/functional/specs/Command Logic/C2588.js create mode 100644 packages/browser/test/functional/specs/Command Logic/C3484892.js create mode 100644 packages/browser/test/functional/specs/Config Overrides/C7437530.js create mode 100644 packages/browser/test/functional/specs/Config Overrides/C7437531.js create mode 100644 packages/browser/test/functional/specs/Config Overrides/C7437532.js create mode 100644 packages/browser/test/functional/specs/Config Overrides/C7437533.js create mode 100644 packages/browser/test/functional/specs/Consent/C14404.js create mode 100644 packages/browser/test/functional/specs/Consent/C14405.js create mode 100644 packages/browser/test/functional/specs/Consent/C14406.js create mode 100644 packages/browser/test/functional/specs/Consent/C14407.js create mode 100644 packages/browser/test/functional/specs/Consent/C14409.js create mode 100644 packages/browser/test/functional/specs/Consent/C14410.js create mode 100644 packages/browser/test/functional/specs/Consent/C14411.js create mode 100644 packages/browser/test/functional/specs/Consent/C14414.js create mode 100644 packages/browser/test/functional/specs/Consent/C1472433.js create mode 100644 packages/browser/test/functional/specs/Consent/C1472434.js create mode 100644 packages/browser/test/functional/specs/Consent/C1472435.js create mode 100644 packages/browser/test/functional/specs/Consent/C1472436.js create mode 100644 packages/browser/test/functional/specs/Consent/C1472437.js create mode 100644 packages/browser/test/functional/specs/Consent/C1472438.js create mode 100644 packages/browser/test/functional/specs/Consent/C1576777.js create mode 100644 packages/browser/test/functional/specs/Consent/C1631712.js create mode 100644 packages/browser/test/functional/specs/Consent/C225953.js create mode 100644 packages/browser/test/functional/specs/Consent/C25148.js create mode 100644 packages/browser/test/functional/specs/Consent/C2593.js create mode 100644 packages/browser/test/functional/specs/Consent/C2594.js create mode 100644 packages/browser/test/functional/specs/Consent/C2660.js create mode 100644 packages/browser/test/functional/specs/Consent/C28754.js create mode 100644 packages/browser/test/functional/specs/Consent/C5594870.js create mode 100644 packages/browser/test/functional/specs/Consent/IAB/C224670.js create mode 100644 packages/browser/test/functional/specs/Consent/IAB/C224671.js create mode 100644 packages/browser/test/functional/specs/Consent/IAB/C224672.js create mode 100644 packages/browser/test/functional/specs/Consent/IAB/C224673.js create mode 100644 packages/browser/test/functional/specs/Consent/IAB/C224674.js create mode 100644 packages/browser/test/functional/specs/Consent/IAB/C224675.js create mode 100644 packages/browser/test/functional/specs/Consent/IAB/C224676.js create mode 100644 packages/browser/test/functional/specs/Consent/IAB/C224677.js create mode 100644 packages/browser/test/functional/specs/Consent/IAB/C224678.js create mode 100644 packages/browser/test/functional/specs/Context/C1911390.js create mode 100644 packages/browser/test/functional/specs/Context/C2597.js create mode 100644 packages/browser/test/functional/specs/Context/C2598.js create mode 100644 packages/browser/test/functional/specs/Context/C2599.js create mode 100644 packages/browser/test/functional/specs/Context/C2600.js create mode 100644 packages/browser/test/functional/specs/Context/C2601.js create mode 100644 packages/browser/test/functional/specs/Context/C7311732.js create mode 100644 packages/browser/test/functional/specs/Data Collector/C11693274.js create mode 100644 packages/browser/test/functional/specs/Data Collector/C1715149.js create mode 100644 packages/browser/test/functional/specs/Data Collector/C225010.js create mode 100644 packages/browser/test/functional/specs/Data Collector/C2592.js create mode 100644 packages/browser/test/functional/specs/Data Collector/C455258.js create mode 100644 packages/browser/test/functional/specs/Data Collector/C75372.js create mode 100644 packages/browser/test/functional/specs/Data Collector/C8118.js create mode 100644 packages/browser/test/functional/specs/Data Collector/C81181.js create mode 100644 packages/browser/test/functional/specs/Data Collector/C81182.js create mode 100644 packages/browser/test/functional/specs/Data Collector/C81183.js create mode 100644 packages/browser/test/functional/specs/Data Collector/C81184.js create mode 100644 packages/browser/test/functional/specs/Data Collector/C8119.js create mode 100644 packages/browser/test/functional/specs/Data Collector/C9369211.js create mode 100644 packages/browser/test/functional/specs/ID Migration/C14394.js create mode 100644 packages/browser/test/functional/specs/ID Migration/C14399.js create mode 100644 packages/browser/test/functional/specs/ID Migration/C14400.js create mode 100644 packages/browser/test/functional/specs/ID Migration/C14401.js create mode 100644 packages/browser/test/functional/specs/ID Migration/C14402.js create mode 100644 packages/browser/test/functional/specs/ID Migration/C14403.js create mode 100644 packages/browser/test/functional/specs/ID Migration/C5752639.js create mode 100644 packages/browser/test/functional/specs/Identity/C10922.js create mode 100644 packages/browser/test/functional/specs/Identity/C14699834.js create mode 100644 packages/browser/test/functional/specs/Identity/C15325238.js create mode 100644 packages/browser/test/functional/specs/Identity/C1703722.js create mode 100644 packages/browser/test/functional/specs/Identity/C1703723.js create mode 100644 packages/browser/test/functional/specs/Identity/C19160486.js create mode 100644 packages/browser/test/functional/specs/Identity/C21636436.js create mode 100644 packages/browser/test/functional/specs/Identity/C21636437.js create mode 100644 packages/browser/test/functional/specs/Identity/C21636438.js create mode 100644 packages/browser/test/functional/specs/Identity/C2581.js create mode 100644 packages/browser/test/functional/specs/Identity/C25822.js create mode 100644 packages/browser/test/functional/specs/Identity/C5287654.js create mode 100644 packages/browser/test/functional/specs/Identity/C5594865.js create mode 100644 packages/browser/test/functional/specs/Identity/C5594866.js create mode 100644 packages/browser/test/functional/specs/Identity/C5594871.js create mode 100644 packages/browser/test/functional/specs/Identity/C5594872.js create mode 100644 packages/browser/test/functional/specs/Identity/C5598188.js create mode 100644 packages/browser/test/functional/specs/Identity/C6842980.js create mode 100644 packages/browser/test/functional/specs/Identity/C6842981.js create mode 100644 packages/browser/test/functional/specs/Identity/C6842982.js create mode 100644 packages/browser/test/functional/specs/Install SDK/C1338399.js create mode 100644 packages/browser/test/functional/specs/Install SDK/C2560.js create mode 100644 packages/browser/test/functional/specs/Install SDK/C2579.js create mode 100644 packages/browser/test/functional/specs/LibraryInfo/C2589.js create mode 100644 packages/browser/test/functional/specs/Location Hints/C6589015.js create mode 100644 packages/browser/test/functional/specs/Location Hints/C6944931.js create mode 100644 packages/browser/test/functional/specs/Logging/C2583.js create mode 100644 packages/browser/test/functional/specs/Logging/C2584.js create mode 100644 packages/browser/test/functional/specs/Logging/C2586.js create mode 100644 packages/browser/test/functional/specs/Logging/C532204.js create mode 100644 packages/browser/test/functional/specs/MediaCollection/MA1.js create mode 100644 packages/browser/test/functional/specs/MediaCollection/MA2.js create mode 100644 packages/browser/test/functional/specs/MediaCollection/MA3.js create mode 100644 packages/browser/test/functional/specs/Migration/C8085773.js create mode 100644 packages/browser/test/functional/specs/Migration/C8085774.js create mode 100644 packages/browser/test/functional/specs/Migration/C8085775.js create mode 100644 packages/browser/test/functional/specs/Migration/C8085776.js create mode 100644 packages/browser/test/functional/specs/Migration/C8085777.js create mode 100644 packages/browser/test/functional/specs/Migration/C8085778.js create mode 100644 packages/browser/test/functional/specs/Migration/C8085779.js create mode 100644 packages/browser/test/functional/specs/Migration/C8085780.js create mode 100644 packages/browser/test/functional/specs/Migration/helper.js create mode 100644 packages/browser/test/functional/specs/Personalization/C11389844.js create mode 100644 packages/browser/test/functional/specs/Personalization/C1234567.js create mode 100644 packages/browser/test/functional/specs/Personalization/C14286730.js create mode 100644 packages/browser/test/functional/specs/Personalization/C14299419.js create mode 100644 packages/browser/test/functional/specs/Personalization/C14299420.js create mode 100644 packages/browser/test/functional/specs/Personalization/C14299421.js create mode 100644 packages/browser/test/functional/specs/Personalization/C14299422.js create mode 100644 packages/browser/test/functional/specs/Personalization/C14317242.js create mode 100644 packages/browser/test/functional/specs/Personalization/C15325239.js create mode 100644 packages/browser/test/functional/specs/Personalization/C17294899.js create mode 100644 packages/browser/test/functional/specs/Personalization/C17409728.js create mode 100644 packages/browser/test/functional/specs/Personalization/C205528.js create mode 100644 packages/browser/test/functional/specs/Personalization/C205529.js create mode 100644 packages/browser/test/functional/specs/Personalization/C21636439.js create mode 100644 packages/browser/test/functional/specs/Personalization/C21886916.js create mode 100644 packages/browser/test/functional/specs/Personalization/C22098199.js create mode 100644 packages/browser/test/functional/specs/Personalization/C28755.js create mode 100644 packages/browser/test/functional/specs/Personalization/C28756.js create mode 100644 packages/browser/test/functional/specs/Personalization/C28757.js create mode 100644 packages/browser/test/functional/specs/Personalization/C28758.js create mode 100644 packages/browser/test/functional/specs/Personalization/C28759.js create mode 100644 packages/browser/test/functional/specs/Personalization/C28760.js create mode 100644 packages/browser/test/functional/specs/Personalization/C3272624.js create mode 100644 packages/browser/test/functional/specs/Personalization/C44363.js create mode 100644 packages/browser/test/functional/specs/Personalization/C5298194.js create mode 100644 packages/browser/test/functional/specs/Personalization/C5805675.js create mode 100644 packages/browser/test/functional/specs/Personalization/C5805676.js create mode 100644 packages/browser/test/functional/specs/Personalization/C6364797.js create mode 100644 packages/browser/test/functional/specs/Personalization/C6364798.js create mode 100644 packages/browser/test/functional/specs/Personalization/C6364799.js create mode 100644 packages/browser/test/functional/specs/Personalization/C6364800.js create mode 100644 packages/browser/test/functional/specs/Personalization/C6984408.js create mode 100644 packages/browser/test/functional/specs/Personalization/C7494472.js create mode 100644 packages/browser/test/functional/specs/Personalization/C7498683.js create mode 100644 packages/browser/test/functional/specs/Personalization/C753469.js create mode 100644 packages/browser/test/functional/specs/Personalization/C753470.js create mode 100644 packages/browser/test/functional/specs/Personalization/C7638574.js create mode 100644 packages/browser/test/functional/specs/Personalization/C782718.js create mode 100644 packages/browser/test/functional/specs/Personalization/C782719.js create mode 100644 packages/browser/test/functional/specs/Personalization/C7878996.js create mode 100644 packages/browser/test/functional/specs/Personalization/C8631576.js create mode 100644 packages/browser/test/functional/specs/Personalization/C8631577.js create mode 100644 packages/browser/test/functional/specs/Personalization/C9932846.js create mode 100644 packages/browser/test/functional/specs/RulesEngine/C13348429.js create mode 100644 packages/browser/test/functional/specs/RulesEngine/C13405889.js create mode 100644 packages/browser/test/functional/specs/RulesEngine/C13419240.js create mode 100644 packages/browser/test/functional/specs/Visitor/C35448.js create mode 100644 packages/browser/test/functional/specs/Visitor/C35450.js create mode 100644 packages/browser/test/functional/specs/Visitor/C36908.js create mode 100644 packages/browser/test/functional/specs/Visitor/C36909.js diff --git a/.testcaferc.json b/.testcaferc.json deleted file mode 100644 index 466cba371..000000000 --- a/.testcaferc.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "src": "packages/**/test/functional/specs/**/*.{mjs,js}", - "skipJsErrors": true, - "disablePageCaching": true -} diff --git a/package.json b/package.json index 86ff9cbde..b1ec0ebc8 100644 --- a/package.json +++ b/package.json @@ -35,10 +35,10 @@ "test:integration:debug": "pnpm exec playwright install chromium && vitest --no-file-parallelism --project=integration --browser=chromium --browser.provider=playwright --browser.headless=false", "test:integration:watch": "pnpm exec playwright install chromium && vitest --project=integration", "test:integration:coverage": "pnpm exec playwright install chromium && vitest run --coverage --project=integration", - "test:functional": "pnpm exec playwright install chromium && EDGE_BASE_PATH=\"ee-pre-prd\" ALLOY_ENV=\"int\" testcafe chromium", - "test:functional:custom": "node scripts/helpers/runFunctionalTests.js", - "test:functional:watch": "pnpm exec playwright install chromium && EDGE_BASE_PATH=\"ee-pre-prd\" ALLOY_ENV=\"int\" ./scripts/watchFunctionalTests.js --browsers chromium", - "test:functional:debug": "pnpm exec playwright install chromium && EDGE_BASE_PATH=\"ee-pre-prd\" ALLOY_ENV=\"int\" testcafe --inspect-brk chromium", + "test:functional": "pnpm --filter @adobe/alloy test:functional", + "test:functional:custom": "pnpm --filter @adobe/alloy test:functional:custom", + "test:functional:watch": "pnpm --filter @adobe/alloy test:functional:watch", + "test:functional:debug": "pnpm --filter @adobe/alloy test:functional:debug", "test:functional:build:int": "pnpm --filter @adobe/alloy test:functional:build:int", "test:functional:build:prod": "pnpm --filter @adobe/alloy test:functional:build:prod", "test:scripts": "vitest run --config=./scripts/specs/vitest.config.js", diff --git a/packages/browser/.testcaferc.json b/packages/browser/.testcaferc.json new file mode 100644 index 000000000..c2fd297c6 --- /dev/null +++ b/packages/browser/.testcaferc.json @@ -0,0 +1,6 @@ +{ + "src": "test/functional/specs/**/*.{mjs,js}", + "skipJsErrors": true, + "disablePageCaching": true +} + diff --git a/packages/browser/package.json b/packages/browser/package.json index 139cc5e8d..4d00772ee 100644 --- a/packages/browser/package.json +++ b/packages/browser/package.json @@ -13,7 +13,13 @@ "scripts": { "build:clean": "rimraf dist distTest", "build": "pnpm run build:clean && rollup -c --environment BASE_CODE_MIN,STANDALONE,STANDALONE_MIN,SERVICE_WORKER,SERVICE_WORKER_MIN,BUNDLESIZE", - "build:watch": "rollup -c --watch" + "build:watch": "rollup -c --watch", + "test:functional": "pnpm exec playwright install chromium && EDGE_BASE_PATH=\"ee-pre-prd\" ALLOY_ENV=\"int\" testcafe chromium", + "test:functional:custom": "node ./scripts/runFunctionalTests.js", + "test:functional:watch": "pnpm exec playwright install chromium && EDGE_BASE_PATH=\"ee-pre-prd\" ALLOY_ENV=\"int\" ../../scripts/watchFunctionalTests.js --browsers chromium", + "test:functional:debug": "pnpm exec playwright install chromium && EDGE_BASE_PATH=\"ee-pre-prd\" ALLOY_ENV=\"int\" testcafe --inspect-brk chromium", + "test:functional:build:int": "rollup -c --environment BASE_CODE_MIN,NPM_PACKAGE_LOCAL,NPM_PACKAGE_LOCAL_MIN", + "test:functional:build:prod": "rollup -c --environment NPM_PACKAGE_PROD,NPM_PACKAGE_PROD_MIN" }, "exports": { ".": "./src/index.js", diff --git a/scripts/helpers/runFunctionalTests.js b/packages/browser/scripts/runFunctionalTests.js similarity index 86% rename from scripts/helpers/runFunctionalTests.js rename to packages/browser/scripts/runFunctionalTests.js index 70ea5c2fb..442247e18 100644 --- a/scripts/helpers/runFunctionalTests.js +++ b/packages/browser/scripts/runFunctionalTests.js @@ -13,10 +13,15 @@ governing permissions and limitations under the License. */ import fs from "fs"; +import path from "path"; import { glob } from "glob"; import createTestCafe from "testcafe"; +import { fileURLToPath } from "url"; -fs.readFile("dist/alloy.js", "utf8", (readFileErr, alloyData) => { +const __dirname = path.dirname(fileURLToPath(import.meta.url)); +const workspaceRoot = path.join(__dirname, "../../../"); + +fs.readFile(path.join(workspaceRoot, "packages/browser/dist/alloy.js"), "utf8", (readFileErr, alloyData) => { if (readFileErr) { console.error(`readFile error: ${readFileErr}`); return; @@ -59,7 +64,7 @@ fs.readFile("dist/alloy.js", "utf8", (readFileErr, alloyData) => { // Generate a glob pattern to match only the included components' test specs const includedComponentsPattern = adjustedComponentNames.join("|"); - const testSpecsGlobPattern = `packages/core/test/functional/specs/@(${includedComponentsPattern})/**/*.js`; + const testSpecsGlobPattern = `${workspaceRoot}packages/browser/test/functional/specs/@(${includedComponentsPattern})/**/*.js`; glob(testSpecsGlobPattern, (globErr, files) => { if (globErr) { diff --git a/scripts/watchFunctionalTests.js b/packages/browser/scripts/watchFunctionalTests.js similarity index 100% rename from scripts/watchFunctionalTests.js rename to packages/browser/scripts/watchFunctionalTests.js diff --git a/packages/browser/test/functional/fixtures/Personalization/C28758.js b/packages/browser/test/functional/fixtures/Personalization/C28758.js new file mode 100644 index 000000000..bcbdd3067 --- /dev/null +++ b/packages/browser/test/functional/fixtures/Personalization/C28758.js @@ -0,0 +1,57 @@ +/* +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. +*/ +export const shadowDomScript = ` + const buyNowContent = \` +
+ +
+
+ +
+
+
+ \`; + customElements.define( + "buy-now-button", + class extends HTMLElement { + constructor() { + super(); + + const shadowRoot = this.attachShadow({ mode: "open" }); + shadowRoot.innerHTML = buyNowContent; + } + } + ); + + const productOrderContent = \`

Product order

Buy
\`; + customElements.define( + "product-order", + class extends HTMLElement { + constructor() { + super(); + + const shadowRoot = this.attachShadow({ mode: "open" }); + shadowRoot.innerHTML = productOrderContent; + } + } + ); +`; + +export const shadowDomFixture = ` +
+ FirstButton + SecondButton + FirstOrder + SecondOrder + +
+ `; diff --git a/packages/browser/test/functional/fixtures/Personalization/C6364800.js b/packages/browser/test/functional/fixtures/Personalization/C6364800.js new file mode 100644 index 000000000..8517452f2 --- /dev/null +++ b/packages/browser/test/functional/fixtures/Personalization/C6364800.js @@ -0,0 +1,80 @@ +/* +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. +*/ +export const testPageHead = ` + + + + + +`; + +export const testPageBody = ` + +
+ + target offer +

+ This is a sample web page. It leverages the Adobe Experience Platform Web + SDK and APIs + to render personalization content. +

+

+ Vestibulum cursus tristique risus, volutpat lobortis quam fermentum dapibus. Sed lacus augue, vulputate a placerat + vel, fringilla sed velit. In aliquet odio ut efficitur gravida. Vivamus volutpat hendrerit nisl ut rutrum. Donec + id nunc dolor. Pellentesque lectus mi, consequat sit amet elit vitae, laoreet euismod est. Cras placerat ex + ligula, nec malesuada dolor feugiat ut. Ut condimentum ante turpis, a iaculis massa cursus vitae. Sed sed felis + quam. Sed hendrerit, nisl vel viverra viverra, nisi mauris laoreet tortor, ut blandit lectus lacus ut tellus. + Integer ante sapien, tincidunt ut erat id, volutpat finibus urna. Aliquam rhoncus tellus vitae facilisis varius. +

+ +
+ + + +
+
+`; diff --git a/packages/browser/test/functional/fixtures/Personalization/C9932846.js b/packages/browser/test/functional/fixtures/Personalization/C9932846.js new file mode 100644 index 000000000..0a9946d4f --- /dev/null +++ b/packages/browser/test/functional/fixtures/Personalization/C9932846.js @@ -0,0 +1,25 @@ +/* +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. +*/ +export const testPageBody = ` +
+
+ +
+
+

AJO Personalization

+
+
+
+ +`; diff --git a/packages/browser/test/functional/fixtures/Personalization/conflictResolution.js b/packages/browser/test/functional/fixtures/Personalization/conflictResolution.js new file mode 100644 index 000000000..88a493ca0 --- /dev/null +++ b/packages/browser/test/functional/fixtures/Personalization/conflictResolution.js @@ -0,0 +1,251 @@ +/* +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. +*/ +export const inAppMessagesPropositions = { + requestId: "09ead9d7-b91f-41d6-9bb5-e7a5396315d6", + handle: [ + { + payload: [ + { + id: "03560676528201411421379778603411811904", + namespace: { + code: "ECID", + }, + }, + ], + type: "identity:result", + }, + { + payload: [ + { + id: "id2", + scope: "web://www.test.com/", + scopeDetails: { + rank: 2, + decisionProvider: "AJO", + correlationID: "3a034993-3bdb-4d8d-870f-0817e8949ebd-0", + characteristics: { + eventToken: + "eyJtZXNzYWdlRXhlY3V0aW9uIjp7Im1lc3NhZ2VFeGVjdXRpb25JRCI6IlVFOkluYm91bmQiLCJtZXNzYWdlSUQiOiIxYmQ4NWMwMC1iNGM5LTQ0NjQtYjIyMC1hYzY5ZTY5NGI1M2QiLCJtZXNzYWdlUHVibGljYXRpb25JRCI6IjNhMDM0OTkzLTNiZGItNGQ4ZC04NzBmLTA4MTdlODk0OWViZCIsIm1lc3NhZ2VUeXBlIjoibWFya2V0aW5nIiwiY2FtcGFpZ25JRCI6IjY4ODg5NDdjLTAyZDQtNDFhNi05YzZjLTE1YTU4ZTVlNzcyYyIsImNhbXBhaWduVmVyc2lvbklEIjoiNDU1NzE2MmQtNzgyMi00Zjg4LTkyZWItMmMxZmViZTFhMmViIiwiY2FtcGFpZ25BY3Rpb25JRCI6ImNhMzJlZjZmLWY3NTItNDA2Ny04YmFlLTE1NGY2MDAyN2E3ZSJ9LCJtZXNzYWdlUHJvZmlsZSI6eyJtZXNzYWdlUHJvZmlsZUlEIjoiYjBlM2M0YjctMWE3YS00NTljLWE2YzUtNTFlNDU0ZDVjYmRiIiwiY2hhbm5lbCI6eyJfaWQiOiJodHRwczovL25zLmFkb2JlLmNvbS94ZG0vY2hhbm5lbHMvaW5BcHAiLCJfdHlwZSI6Imh0dHBzOi8vbnMuYWRvYmUuY29tL3hkbS9jaGFubmVsLXR5cGVzL2luQXBwIn19fQ==", + }, + activity: { + id: "6888947c-02d4-41a6-9c6c-15a58e5e772c#ca32ef6f-f752-4067-8bae-154f60027a7e", + matchedSurfaces: ["web://surface1/"], + }, + }, + items: [ + { + id: "e1090531-caee-4749-a738-680f393cf4a9", + schema: "https://ns.adobe.com/personalization/ruleset-item", + data: { + version: 1, + rules: [ + { + condition: { + definition: { + key: "~type", + matcher: "eq", + values: ["com.adobe.eventType.rulesEngine"], + }, + type: "matcher", + }, + consequences: [ + { + id: "f03980c9-5344-4e32-84c7-d74ffebf06d6", + type: "schema", + detail: { + id: "f03980c9-5344-4e32-84c7-d74ffebf06d6", + schema: + "https://ns.adobe.com/personalization/message/in-app", + data: { + content: + "Proposition 2", + contentType: "text/html", + remoteAssets: [ + "https://cdn.experience.adobe.net/solutions/cjm-inapp-editor/assets/InAppBlockImageDefault.aa849e19.svg", + ], + webParameters: { + "alloy-content-iframe": { + style: { + border: "none", + height: "100%", + width: "100%", + }, + params: { + enabled: true, + insertionMethod: "appendChild", + parentElement: "#alloy-messaging-container", + }, + }, + "alloy-messaging-container": { + style: { + backgroundColor: "#000000", + border: "none", + borderRadius: "15px", + height: "100vh", + overflow: "hidden", + position: "fixed", + width: "100%", + left: "50%", + transform: + "translateX(-50%) translateY(-50%)", + top: "50%", + }, + params: { + enabled: true, + insertionMethod: "appendChild", + parentElement: "body", + }, + }, + "alloy-overlay-container": { + style: { + position: "fixed", + top: "0", + left: "0", + width: "100%", + height: "100%", + background: "transparent", + opacity: 0.2, + backgroundColor: "#000000", + }, + params: { + enabled: true, + insertionMethod: "appendChild", + parentElement: "body", + }, + }, + }, + publishedDate: 1727568749, + }, + }, + }, + ], + }, + ], + }, + }, + ], + }, + { + id: "id1", + scope: "web://www.test.com/", + scopeDetails: { + rank: 1, + decisionProvider: "AJO", + correlationID: "d4f5d677-1123-4605-ad9e-86fead923220-0", + characteristics: { + eventToken: + "eyJtZXNzYWdlRXhlY3V0aW9uIjp7Im1lc3NhZ2VFeGVjdXRpb25JRCI6IlVFOkluYm91bmQiLCJtZXNzYWdlSUQiOiJiNmY1ODVmZS1mNWE1LTQ0NWUtYjU0OC0yOThlMmQ1MDFkZTYiLCJtZXNzYWdlUHVibGljYXRpb25JRCI6ImQ0ZjVkNjc3LTExMjMtNDYwNS1hZDllLTg2ZmVhZDkyMzIyMCIsIm1lc3NhZ2VUeXBlIjoibWFya2V0aW5nIiwiY2FtcGFpZ25JRCI6ImI3NWNkNDAyLTIwNzMtNDc5OC1hMDJjLTc0YmQyMDg0MmQyNyIsImNhbXBhaWduVmVyc2lvbklEIjoiMmExMDJjZDMtZmM0NC00ZDI0LWEzMWMtNzZhZTBmY2FjMWJhIiwiY2FtcGFpZ25BY3Rpb25JRCI6ImNhMzJlZjZmLWY3NTItNDA2Ny04YmFlLTE1NGY2MDAyN2E3ZSJ9LCJtZXNzYWdlUHJvZmlsZSI6eyJtZXNzYWdlUHJvZmlsZUlEIjoiNzEyZjYwN2UtNjNmNS00NGExLTg3ZDYtM2Y1NWQzYjVmNGM2IiwiY2hhbm5lbCI6eyJfaWQiOiJodHRwczovL25zLmFkb2JlLmNvbS94ZG0vY2hhbm5lbHMvaW5BcHAiLCJfdHlwZSI6Imh0dHBzOi8vbnMuYWRvYmUuY29tL3hkbS9jaGFubmVsLXR5cGVzL2luQXBwIn19fQ==", + }, + activity: { + id: "b75cd402-2073-4798-a02c-74bd20842d27#ca32ef6f-f752-4067-8bae-154f60027a7e", + matchedSurfaces: ["web://surface1/"], + }, + }, + items: [ + { + id: "471af8f8-7806-47ce-885e-45fffe14108a", + schema: "https://ns.adobe.com/personalization/ruleset-item", + data: { + version: 1, + rules: [ + { + condition: { + definition: { + key: "~type", + matcher: "eq", + values: ["com.adobe.eventType.rulesEngine"], + }, + type: "matcher", + }, + consequences: [ + { + id: "613e9843-7291-4505-9cca-3f76caff6bec", + type: "schema", + detail: { + id: "613e9843-7291-4505-9cca-3f76caff6bec", + schema: + "https://ns.adobe.com/personalization/message/in-app", + data: { + content: + "Proposition 1", + contentType: "text/html", + remoteAssets: [ + "https://cdn.experience.adobe.net/solutions/cjm-inapp-editor/assets/InAppBlockImageDefault.aa849e19.svg", + ], + webParameters: { + "alloy-content-iframe": { + style: { + border: "none", + height: "100%", + width: "100%", + }, + params: { + enabled: true, + insertionMethod: "appendChild", + parentElement: "#alloy-messaging-container", + }, + }, + "alloy-messaging-container": { + style: { + backgroundColor: "#000000", + border: "none", + borderRadius: "15px", + height: "100vh", + overflow: "hidden", + position: "fixed", + width: "100%", + left: "50%", + transform: + "translateX(-50%) translateY(-50%)", + top: "50%", + }, + params: { + enabled: true, + insertionMethod: "appendChild", + parentElement: "body", + }, + }, + "alloy-overlay-container": { + style: { + position: "fixed", + top: "0", + left: "0", + width: "100%", + height: "100%", + background: "transparent", + opacity: 0.2, + backgroundColor: "#000000", + }, + params: { + enabled: true, + insertionMethod: "appendChild", + parentElement: "body", + }, + }, + }, + publishedDate: 1727568995, + }, + }, + }, + ], + }, + ], + }, + }, + ], + }, + ], + type: "personalization:decisions", + eventIndex: 0, + }, + ], +}; diff --git a/packages/browser/test/functional/helpers/areThirdPartyCookiesSupported.js b/packages/browser/test/functional/helpers/areThirdPartyCookiesSupported.js new file mode 100644 index 000000000..ec79f779d --- /dev/null +++ b/packages/browser/test/functional/helpers/areThirdPartyCookiesSupported.js @@ -0,0 +1,30 @@ +/* +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 } from "testcafe"; +import { + CHROME, + CHROMIUM, + EDGE, + INTERNET_EXPLORER, +} from "./constants/browsers.js"; + +const browsersSupportingThirdPartyCookiesByDefault = [ + CHROME, + CHROMIUM, + EDGE, + INTERNET_EXPLORER, +]; + +// This must be a function called during the test, otherwise TestCafe will throw +// an error about how it can't resolve the right context for "t". +export default () => + browsersSupportingThirdPartyCookiesByDefault.indexOf(t.browser.name) !== -1; diff --git a/packages/browser/test/functional/helpers/assertions/advertising.js b/packages/browser/test/functional/helpers/assertions/advertising.js new file mode 100644 index 000000000..cec1babae --- /dev/null +++ b/packages/browser/test/functional/helpers/assertions/advertising.js @@ -0,0 +1,217 @@ +/* +Copyright 2025 Adobe. All rights reserved. +This file is licensed to you under the Apache License, Version 2.0 (the "License"); +*/ +import { t } from "testcafe"; + +// Constants +export const ADVERTISING_CONSTANTS = Object.freeze({ + DEFAULT_ADVERTISER_SETTINGS: [ + { advertiserId: "83565", enabled: true }, + { advertiserId: "83567", enabled: true }, + { advertiserId: "83569", enabled: true }, + ], + DEFAULT_ADVERTISER_IDS_STRING: "83565, 83567, 83569", + DEFAULT_TIMEOUT: 15000, + EVENT_TYPES: { + CLICK_THROUGH: "advertising.enrichment_ct", + VIEW_THROUGH: "advertising.enrichment", + }, + ID5_PARTNER_ID: "173", + RAMP_ID_JS_PATH: "https://cdn.jsdelivr.net/npm/@liveramp/ats@2/ats.min.js", + EXPERIENCE_STRING: "_experience", + SAMPLE_SURFER_ID: "sample-surfer-id-12345", +}); + +// Helpers +const parseBody = (req) => { + try { + return JSON.parse(req?.request?.body) || {}; + } catch { + return {}; + } +}; + +const expectPath = async (obj, path, msg) => { + const val = path.split(".").reduce((o, k) => o?.[k], obj); + await t.expect(val).ok(msg); +}; + +// Config builder +export const createAdvertisingConfig = ({ + advertiserSettings = ADVERTISING_CONSTANTS.DEFAULT_ADVERTISER_SETTINGS, + id5PartnerId, + rampIdJSPath, + dspEnabled = true, +} = {}) => ({ + advertising: { + ...(advertiserSettings && { advertiserSettings }), + ...(id5PartnerId && { id5PartnerId }), + ...(rampIdJSPath && { rampIdJSPath }), + dspEnabled, + }, +}); + +// Finders +export const findClickThroughRequest = (requests) => + requests.find((req) => { + const body = parseBody(req); + const event = body.events?.[0]; + + const xdm = event?.xdm; + const eventType = xdm?.eventType; + + return eventType === ADVERTISING_CONSTANTS.EVENT_TYPES.CLICK_THROUGH; + }) || null; + +export const findViewThroughRequests = (requests) => + requests.filter((req) => { + const body = parseBody(req); + const event = body.events?.[0]; + + const hasAdvertisingQuery = !!event?.query?.advertising; + const hasViewThroughEventType = + event?.xdm?.eventType === ADVERTISING_CONSTANTS.EVENT_TYPES.VIEW_THROUGH; + + return hasAdvertisingQuery || hasViewThroughEventType; + }); + +export const findViewThroughRequestsWithXDM = (requests) => + requests.filter((req) => { + const body = parseBody(req); + const event = body.events?.[0]; + + return ( + event?.xdm?.eventType === ADVERTISING_CONSTANTS.EVENT_TYPES.VIEW_THROUGH + ); + }); + +// Validator for click-through +export const validateClickThroughRequest = async (req, expected) => { + const body = parseBody(req); + await expectPath(body, "events", "Missing events"); + + await t.expect(body.events.length).gte(1, "No events"); + + const adCloud = + body.events[0]?.xdm?.[ADVERTISING_CONSTANTS.EXPERIENCE_STRING]?.adcloud; + await t.expect(adCloud).ok("Missing adcloud"); + + const conversionDetails = adCloud.conversionDetails; + await t.expect(conversionDetails).ok("Missing conversionDetails"); + + // Validate eventType at the top level + const eventType = body.events[0]?.xdm?.eventType; + await t + .expect(eventType) + .eql("advertising.enrichment_ct", "eventType mismatch"); + + // Validate tracking code (skwcid) + if (expected.sampleGroupId !== undefined) { + await t + .expect(conversionDetails.trackingCode) + .eql(expected.sampleGroupId, "trackingCode mismatch"); + } + + // Validate tracking identities (efid) + if (expected.experimentId !== undefined) { + await t + .expect(conversionDetails.trackingIdentities) + .eql(expected.experimentId, "trackingIdentities mismatch"); + } +}; + +// Validator for view-through +export const validateViewThroughRequest = async (req, expected) => { + const body = parseBody(req); + await expectPath(body, "events", "Missing events"); + await t.expect(body.events.length).gte(1, "No events"); + + const event = body.events[0]; + + const eventType = event?.xdm?.eventType; + if (eventType) { + await t + .expect(eventType) + .eql( + ADVERTISING_CONSTANTS.EVENT_TYPES.VIEW_THROUGH, + "eventType should be advertising.enrichment for view-through", + ); + } + + const conv = event?.query?.advertising; + await t.expect(conv).ok("Missing advertising query"); + + await t.expect(conv.advIds).eql(expected.advIds, "advIds mismatch"); + + if (expected.requireIds !== false) { + const ids = conv.stitchIds || {}; + await t.expect(ids.surferId || ids.id5 || ids.rampIDEnv).ok("No IDs"); + } + + if (conv.lastDisplayClick) + await t.expect(typeof conv.lastDisplayClick).eql("string"); + if (conv.lastSearchClick) + await t.expect(typeof conv.lastSearchClick).eql("number"); +}; + +export const validateViewThroughRequestWithXDM = async (req, expected) => { + const body = parseBody(req); + await expectPath(body, "events", "Missing events"); + await t.expect(body.events.length).gte(1, "No events"); + + const event = body.events[0]; + + const eventType = event?.xdm?.eventType; + await t + .expect(eventType) + .eql( + ADVERTISING_CONSTANTS.EVENT_TYPES.VIEW_THROUGH, + "eventType should be advertising.enrichment for XDM view-through", + ); + + const conv = event?.query?.advertising; + await t.expect(conv).ok("Missing advertising query"); + + await t.expect(conv.advIds).eql(expected.advIds, "advIds mismatch"); + + if (expected.requireIds !== false) { + const ids = conv.stitchIds || {}; + await t.expect(ids.surferId || ids.id5 || ids.rampIDEnv).ok("No IDs"); + } + + if (conv.lastDisplayClick) + await t.expect(typeof conv.lastDisplayClick).eql("string"); + if (conv.lastSearchClick) + await t.expect(typeof conv.lastSearchClick).eql("number"); +}; + +// Best request selector +export const findBestRequestWithAdvertisingIds = (requests) => { + const viewReqs = findViewThroughRequests(requests); + if (viewReqs.length === 0) { + return null; + } + + let best = null; + let max = 0; + + viewReqs.forEach((r) => { + const stitch = + parseBody(r).events?.[0]?.query?.advertising?.stitchIds || {}; + const count = ["surferId", "id5", "rampIDEnv"].reduce( + (sum, key) => sum + (stitch[key] ? 1 : 0), + 0, + ); + if (count > max) { + max = count; + best = r; + } + }); + + // Always return at least the first request, with whatever maxIds we found + return { + bestRequest: best || viewReqs[0], + maxIds: max, + }; +}; diff --git a/packages/browser/test/functional/helpers/assertions/index.js b/packages/browser/test/functional/helpers/assertions/index.js new file mode 100644 index 000000000..5aa8d4d79 --- /dev/null +++ b/packages/browser/test/functional/helpers/assertions/index.js @@ -0,0 +1,13 @@ +/* +Copyright 2025 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. +*/ +// Please keep in alphabetical order. +export { default as responseStatus } from "./responseStatus.js"; diff --git a/packages/browser/test/functional/helpers/assertions/responseStatus.js b/packages/browser/test/functional/helpers/assertions/responseStatus.js new file mode 100644 index 000000000..b9ba7778f --- /dev/null +++ b/packages/browser/test/functional/helpers/assertions/responseStatus.js @@ -0,0 +1,32 @@ +/* +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 } from "testcafe"; + +const responseStatus = async (networkLogs, statuses) => { + if (!Array.isArray(statuses)) { + statuses = [statuses]; + } + + for (let i = 0; i < networkLogs.length; i += 1) { + const req = networkLogs[i]; + // TODO: Check why some requests don't have responses. + // TODO: It looks like test cafe might not be handling gzip correctly. + if (req.response) { + // eslint-disable-next-line no-await-in-loop + await t + .expect(statuses.includes(req.response.statusCode)) + .ok(`expected ${statuses} to be found in ${req.response.statusCode}`); + } + } +}; + +export default responseStatus; diff --git a/packages/browser/test/functional/helpers/configureAlloyInstance/index.js b/packages/browser/test/functional/helpers/configureAlloyInstance/index.js new file mode 100644 index 000000000..c0b4d28db --- /dev/null +++ b/packages/browser/test/functional/helpers/configureAlloyInstance/index.js @@ -0,0 +1,27 @@ +/* +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 { ClientFunction } from "testcafe"; + +const configureAlloyInstance = ClientFunction((instanceName, cfg) => { + let finalInstanceName = instanceName; + let finalConfig = cfg; + + // Default instanceName to `alloy`. + if (typeof instanceName === "object" && instanceName !== null) { + finalInstanceName = "alloy"; + finalConfig = instanceName; + } + + return window[finalInstanceName]("configure", finalConfig); +}); + +export default configureAlloyInstance; diff --git a/packages/browser/test/functional/helpers/consoleLogger/index.js b/packages/browser/test/functional/helpers/consoleLogger/index.js new file mode 100644 index 000000000..be36c503b --- /dev/null +++ b/packages/browser/test/functional/helpers/consoleLogger/index.js @@ -0,0 +1,147 @@ +/* +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 } from "testcafe"; + +const logLevels = ["log", "info", "warn", "error"]; + +const containsMessageMatchingRegex = (messages, messageRegex) => + messages.find((message) => messageRegex.test(message)) !== undefined; + +const formatFoundMessages = (messages) => { + if (!messages.length) { + return "No messages found."; + } + + return `Messages found:\n${messages.join("\n")}`; +}; + +/** + * Creates an object that can used for asserting the messages are or are not + * logged. The assertions will be made again all messages that occur after the + * logger has been created. + * + * For each log level (log, info, warn, error), there are assertion methods + * available. + * + * For example, here is how you would test that, at the "warn" + * log level, a message matching a given regex was logged: + * + * await logger.warn.expectMessageMatching(/test/); + * + * Here is how you would test that, at the "warn" log level, no messages + * matching a given regex was logged: + * + * await logger.warn.expectNoMessageMatching(/test/); + * + * Here is how you would test that, at the "warn log level, no messages + * were logged: + * + * await logger.warn.expectNoMessages(); + * + * There is also a method directly on the logger that resets all messages at + * all log levels: + * + * await logger.reset(); + */ +const createConsoleLogger = async () => { + let cursorByLogLevel; + const updateCursorByLogLevel = (messages) => { + cursorByLogLevel = logLevels.reduce((memo, logLevel) => { + memo[logLevel] = messages[logLevel].length; + return memo; + }, {}); + }; + + const messagesWhenCreated = await t.getBrowserConsoleMessages(); + updateCursorByLogLevel(messagesWhenCreated); + + // testCafe just calls toString on each parameter to the console log, so when + // logging objects, it just shows [object Object]. So this JSON stringifys the + // args and logs that. + await t.eval( + () => { + logLevels.forEach((logLevel) => { + const original = window.console[logLevel]; + window.console[logLevel] = (...args) => original(JSON.stringify(args)); + }); + }, + { dependencies: { logLevels } }, + ); + + const getMessagesSinceReset = async (logLevel) => { + const consoleMessages = await t.getBrowserConsoleMessages(); + const messagesForLevel = consoleMessages[logLevel]; + return messagesForLevel + .slice(cursorByLogLevel[logLevel]) + .map((message) => JSON.parse(message)); + }; + + const getMessagesSinceResetAsStrings = async (logLevel) => { + const messages = await getMessagesSinceReset(logLevel); + return messages.map((message) => + message.map((part) => part?.toString()).join(" "), + ); + }; + + const reset = async () => { + const messages = await t.getBrowserConsoleMessages(); + updateCursorByLogLevel(messages); + }; + + const expectMessageMatching = async (logLevel, messageRegex) => { + const messages = await getMessagesSinceResetAsStrings(logLevel); + await t + .expect(containsMessageMatchingRegex(messages, messageRegex)) + .ok( + `No message was found at "${logLevel}" log level matching ${messageRegex}. ${formatFoundMessages( + messages, + )}`, + ); + }; + + const expectNoMessageMatching = async (logLevel, messageRegex) => { + const messages = await getMessagesSinceResetAsStrings(logLevel); + await t + .expect(containsMessageMatchingRegex(messages, messageRegex)) + .notOk( + `A message was found at "${logLevel}" log level matching ${messageRegex} when none was expected.`, + ); + }; + + const expectNoMessages = async (logLevel) => { + const messages = await getMessagesSinceResetAsStrings(logLevel); + await t + .expect(messages.length) + .notOk( + `Messages were found "${logLevel}" at log level when none were expected. ${formatFoundMessages( + messages, + )}`, + ); + }; + + const methodsByLogLevel = logLevels.reduce((memo, logLevel) => { + memo[logLevel] = { + expectMessageMatching: expectMessageMatching.bind(null, logLevel), + expectNoMessageMatching: expectNoMessageMatching.bind(null, logLevel), + expectNoMessages: expectNoMessages.bind(null, logLevel), + getMessagesSinceReset: getMessagesSinceReset.bind(null, logLevel), + }; + return memo; + }, {}); + + return { + reset, + ...methodsByLogLevel, + }; +}; + +export default createConsoleLogger; diff --git a/packages/browser/test/functional/helpers/constants/alloyEnvironment.js b/packages/browser/test/functional/helpers/constants/alloyEnvironment.js new file mode 100644 index 000000000..2366725d0 --- /dev/null +++ b/packages/browser/test/functional/helpers/constants/alloyEnvironment.js @@ -0,0 +1,14 @@ +/* +Copyright 2021 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. +*/ + +export const INTEGRATION = "int"; +export const PRODUCTION = "prod"; diff --git a/packages/browser/test/functional/helpers/constants/browsers.js b/packages/browser/test/functional/helpers/constants/browsers.js new file mode 100644 index 000000000..d61d2f5d2 --- /dev/null +++ b/packages/browser/test/functional/helpers/constants/browsers.js @@ -0,0 +1,19 @@ +/* +Copyright 2020 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. +*/ + +// The values here match those listed in +// https://github.com/lancedikson/bowser/blob/9ecf3e94c3269ef8bb4c8274dab6a31eea665aea/src/constants.js +// which is the library that provides the value for t.browser.name. +export const CHROME = "Chrome"; +export const CHROMIUM = "Chromium"; +export const EDGE = "Microsoft Edge"; +export const INTERNET_EXPLORER = "Internet Explorer"; diff --git a/packages/browser/test/functional/helpers/constants/configParts/ajoConfigForStage.js b/packages/browser/test/functional/helpers/constants/configParts/ajoConfigForStage.js new file mode 100644 index 000000000..6d79fcce5 --- /dev/null +++ b/packages/browser/test/functional/helpers/constants/configParts/ajoConfigForStage.js @@ -0,0 +1,17 @@ +/* +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. +*/ +export default { + edgeDomain: "edge-int.adobedc.net", + datastreamId: "19fc5fe9-37df-46da-8f5c-9eeff4f75ed9", + orgId: "745F37C35E4B776E0A49421B@AdobeOrg", + edgeBasePath: "ee", +}; diff --git a/packages/browser/test/functional/helpers/constants/configParts/clickCollectionDisabled.js b/packages/browser/test/functional/helpers/constants/configParts/clickCollectionDisabled.js new file mode 100644 index 000000000..52e4cd9d8 --- /dev/null +++ b/packages/browser/test/functional/helpers/constants/configParts/clickCollectionDisabled.js @@ -0,0 +1,14 @@ +/* +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. +*/ +export default { + clickCollectionEnabled: false, +}; diff --git a/packages/browser/test/functional/helpers/constants/configParts/clickCollectionEnabled.js b/packages/browser/test/functional/helpers/constants/configParts/clickCollectionEnabled.js new file mode 100644 index 000000000..f1bbcfd94 --- /dev/null +++ b/packages/browser/test/functional/helpers/constants/configParts/clickCollectionEnabled.js @@ -0,0 +1,14 @@ +/* +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. +*/ +export default { + clickCollectionEnabled: true, +}; diff --git a/packages/browser/test/functional/helpers/constants/configParts/clickCollectionEventGroupingDisabled.js b/packages/browser/test/functional/helpers/constants/configParts/clickCollectionEventGroupingDisabled.js new file mode 100644 index 000000000..977a75658 --- /dev/null +++ b/packages/browser/test/functional/helpers/constants/configParts/clickCollectionEventGroupingDisabled.js @@ -0,0 +1,16 @@ +/* +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. +*/ +export default { + clickCollection: { + eventGroupingEnabled: false, + }, +}; diff --git a/packages/browser/test/functional/helpers/constants/configParts/clickCollectionSessionStorageDisabled.js b/packages/browser/test/functional/helpers/constants/configParts/clickCollectionSessionStorageDisabled.js new file mode 100644 index 000000000..67daa8943 --- /dev/null +++ b/packages/browser/test/functional/helpers/constants/configParts/clickCollectionSessionStorageDisabled.js @@ -0,0 +1,16 @@ +/* +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. +*/ +export default { + clickCollection: { + sessionStorageEnabled: false, + }, +}; diff --git a/packages/browser/test/functional/helpers/constants/configParts/configOverridesAlt.js b/packages/browser/test/functional/helpers/constants/configParts/configOverridesAlt.js new file mode 100644 index 000000000..36646d777 --- /dev/null +++ b/packages/browser/test/functional/helpers/constants/configParts/configOverridesAlt.js @@ -0,0 +1,29 @@ +/* +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. +*/ +export default { + com_adobe_experience_platform: { + datasets: { + event: { + datasetId: "6336ff95ba16ca1c07b4c0db", + }, + }, + }, + com_adobe_analytics: { + reportSuites: ["unifiedjsqeonlymobileweb"], + }, + com_adobe_identity: { + idSyncContainerId: 30794, + }, + com_adobe_target: { + propertyToken: "aba5431a-9f59-f816-7d73-8e40c8f4c4fd", + }, +}; diff --git a/packages/browser/test/functional/helpers/constants/configParts/configOverridesMain.js b/packages/browser/test/functional/helpers/constants/configParts/configOverridesMain.js new file mode 100644 index 000000000..6748412e2 --- /dev/null +++ b/packages/browser/test/functional/helpers/constants/configParts/configOverridesMain.js @@ -0,0 +1,29 @@ +/* +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. +*/ +export default { + com_adobe_experience_platform: { + datasets: { + event: { + datasetId: "6335faf30f5a161c0b4b1444", + }, + }, + }, + com_adobe_analytics: { + reportSuites: ["unifiedjsqeonly2"], + }, + com_adobe_identity: { + idSyncContainerId: 30793, + }, + com_adobe_target: { + propertyToken: "a15d008c-5ec0-cabd-7fc7-ab54d56f01e8", + }, +}; diff --git a/packages/browser/test/functional/helpers/constants/configParts/consentIn.js b/packages/browser/test/functional/helpers/constants/configParts/consentIn.js new file mode 100644 index 000000000..25f3aa05b --- /dev/null +++ b/packages/browser/test/functional/helpers/constants/configParts/consentIn.js @@ -0,0 +1,14 @@ +/* +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. +*/ +export default { + defaultConsent: "in", +}; diff --git a/packages/browser/test/functional/helpers/constants/configParts/consentPending.js b/packages/browser/test/functional/helpers/constants/configParts/consentPending.js new file mode 100644 index 000000000..40fd39cbb --- /dev/null +++ b/packages/browser/test/functional/helpers/constants/configParts/consentPending.js @@ -0,0 +1,14 @@ +/* +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. +*/ +export default { + defaultConsent: "pending", +}; diff --git a/packages/browser/test/functional/helpers/constants/configParts/debugDisabled.js b/packages/browser/test/functional/helpers/constants/configParts/debugDisabled.js new file mode 100644 index 000000000..5e6d1f28e --- /dev/null +++ b/packages/browser/test/functional/helpers/constants/configParts/debugDisabled.js @@ -0,0 +1,14 @@ +/* +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. +*/ +export default { + debugEnabled: false, +}; diff --git a/packages/browser/test/functional/helpers/constants/configParts/debugEnabled.js b/packages/browser/test/functional/helpers/constants/configParts/debugEnabled.js new file mode 100644 index 000000000..707d5c1b4 --- /dev/null +++ b/packages/browser/test/functional/helpers/constants/configParts/debugEnabled.js @@ -0,0 +1,14 @@ +/* +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. +*/ +export default { + debugEnabled: true, +}; diff --git a/packages/browser/test/functional/helpers/constants/configParts/edgeDomainFirstParty.js b/packages/browser/test/functional/helpers/constants/configParts/edgeDomainFirstParty.js new file mode 100644 index 000000000..13d865bd2 --- /dev/null +++ b/packages/browser/test/functional/helpers/constants/configParts/edgeDomainFirstParty.js @@ -0,0 +1,16 @@ +/* +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 { FIRST_PARTY_DOMAIN } from "../domain.js"; + +export default { + edgeDomain: FIRST_PARTY_DOMAIN, +}; diff --git a/packages/browser/test/functional/helpers/constants/configParts/edgeDomainThirdParty.js b/packages/browser/test/functional/helpers/constants/configParts/edgeDomainThirdParty.js new file mode 100644 index 000000000..0b0f37be8 --- /dev/null +++ b/packages/browser/test/functional/helpers/constants/configParts/edgeDomainThirdParty.js @@ -0,0 +1,16 @@ +/* +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 { THIRD_PARTY_DOMAIN } from "../domain.js"; + +export default { + edgeDomain: THIRD_PARTY_DOMAIN, +}; diff --git a/packages/browser/test/functional/helpers/constants/configParts/index.js b/packages/browser/test/functional/helpers/constants/configParts/index.js new file mode 100644 index 000000000..84b0b509a --- /dev/null +++ b/packages/browser/test/functional/helpers/constants/configParts/index.js @@ -0,0 +1,57 @@ +/* +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 configOverridesMain from "./configOverridesMain.js"; +import configOverridesAlt from "./configOverridesAlt.js"; +import orgMainConfigMain from "./orgMainConfigMain.js"; +import orgAltConfigAlt from "./orgAltConfigAlt.js"; +import debugEnabled from "./debugEnabled.js"; +import debugDisabled from "./debugDisabled.js"; +import edgeDomainFirstParty from "./edgeDomainFirstParty.js"; +import edgeDomainThirdParty from "./edgeDomainThirdParty.js"; +import clickCollectionEnabled from "./clickCollectionEnabled.js"; +import clickCollectionDisabled from "./clickCollectionDisabled.js"; +import clickCollectionSessionStorageDisabled from "./clickCollectionSessionStorageDisabled.js"; +import clickCollectionEventGroupingDisabled from "./clickCollectionEventGroupingDisabled.js"; +import migrationEnabled from "./migrationEnabled.js"; +import targetMigrationEnabled from "./targetMigrationEnabled.js"; +import migrationDisabled from "./migrationDisabled.js"; +import consentIn from "./consentIn.js"; +import consentPending from "./consentPending.js"; +import thirdPartyCookiesEnabled from "./thirdPartyCookiesEnabled.js"; +import thirdPartyCookiesDisabled from "./thirdPartyCookiesDisabled.js"; +import ajoConfigForStage from "./ajoConfigForStage.js"; + +const compose = (...objects) => Object.assign({}, ...objects); + +export { + compose, + configOverridesMain, + configOverridesAlt, + orgMainConfigMain, + orgAltConfigAlt, + debugEnabled, + debugDisabled, + edgeDomainFirstParty, + edgeDomainThirdParty, + clickCollectionEnabled, + clickCollectionDisabled, + clickCollectionSessionStorageDisabled, + clickCollectionEventGroupingDisabled, + migrationEnabled, + migrationDisabled, + consentIn, + consentPending, + thirdPartyCookiesEnabled, + thirdPartyCookiesDisabled, + targetMigrationEnabled, + ajoConfigForStage, +}; diff --git a/packages/browser/test/functional/helpers/constants/configParts/migrationDisabled.js b/packages/browser/test/functional/helpers/constants/configParts/migrationDisabled.js new file mode 100644 index 000000000..13c60db23 --- /dev/null +++ b/packages/browser/test/functional/helpers/constants/configParts/migrationDisabled.js @@ -0,0 +1,14 @@ +/* +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. +*/ +export default { + idMigrationEnabled: false, +}; diff --git a/packages/browser/test/functional/helpers/constants/configParts/migrationEnabled.js b/packages/browser/test/functional/helpers/constants/configParts/migrationEnabled.js new file mode 100644 index 000000000..9fde41f17 --- /dev/null +++ b/packages/browser/test/functional/helpers/constants/configParts/migrationEnabled.js @@ -0,0 +1,14 @@ +/* +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. +*/ +export default { + idMigrationEnabled: true, +}; diff --git a/packages/browser/test/functional/helpers/constants/configParts/orgAltConfigAlt.js b/packages/browser/test/functional/helpers/constants/configParts/orgAltConfigAlt.js new file mode 100644 index 000000000..d54c4e783 --- /dev/null +++ b/packages/browser/test/functional/helpers/constants/configParts/orgAltConfigAlt.js @@ -0,0 +1,16 @@ +/* +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. +*/ +// TODO: Use a real config ID since 9999999 is going away. +// TODO: Need configs in `int` & prod`. +import getBaseConfig from "../../getBaseConfig.js"; + +export default getBaseConfig("53A16ACB5CC1D3760A495C99@AdobeOrg", "9999999"); diff --git a/packages/browser/test/functional/helpers/constants/configParts/orgMainConfigMain.js b/packages/browser/test/functional/helpers/constants/configParts/orgMainConfigMain.js new file mode 100644 index 000000000..f9af8b099 --- /dev/null +++ b/packages/browser/test/functional/helpers/constants/configParts/orgMainConfigMain.js @@ -0,0 +1,14 @@ +/* +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 getBaseConfig from "../../getBaseConfig.js"; + +export default getBaseConfig(); diff --git a/packages/browser/test/functional/helpers/constants/configParts/orgMediaConfig.js b/packages/browser/test/functional/helpers/constants/configParts/orgMediaConfig.js new file mode 100644 index 000000000..23acf6272 --- /dev/null +++ b/packages/browser/test/functional/helpers/constants/configParts/orgMediaConfig.js @@ -0,0 +1,17 @@ +/* +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 getBaseConfig from "../../getBaseConfig.js"; + +export default getBaseConfig( + "97D1F3F459CE0AD80A495CBE@AdobeOrg", + "27dae196-8c75-4eed-82d1-3895616f85d6", +); diff --git a/packages/browser/test/functional/helpers/constants/configParts/streamingMedia.js b/packages/browser/test/functional/helpers/constants/configParts/streamingMedia.js new file mode 100644 index 000000000..aa30aca69 --- /dev/null +++ b/packages/browser/test/functional/helpers/constants/configParts/streamingMedia.js @@ -0,0 +1,17 @@ +/* +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. +*/ +export default { + streamingMedia: { + channel: "functional tests channel", + playerName: "functional test player", + }, +}; diff --git a/packages/browser/test/functional/helpers/constants/configParts/targetMigrationEnabled.js b/packages/browser/test/functional/helpers/constants/configParts/targetMigrationEnabled.js new file mode 100644 index 000000000..7e119414e --- /dev/null +++ b/packages/browser/test/functional/helpers/constants/configParts/targetMigrationEnabled.js @@ -0,0 +1,14 @@ +/* +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. +*/ +export default { + targetMigrationEnabled: true, +}; diff --git a/packages/browser/test/functional/helpers/constants/configParts/thirdPartyCookiesDisabled.js b/packages/browser/test/functional/helpers/constants/configParts/thirdPartyCookiesDisabled.js new file mode 100644 index 000000000..152107765 --- /dev/null +++ b/packages/browser/test/functional/helpers/constants/configParts/thirdPartyCookiesDisabled.js @@ -0,0 +1,15 @@ +/* +Copyright 2020 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. +*/ + +export default { + thirdPartyCookiesEnabled: false, +}; diff --git a/packages/browser/test/functional/helpers/constants/configParts/thirdPartyCookiesEnabled.js b/packages/browser/test/functional/helpers/constants/configParts/thirdPartyCookiesEnabled.js new file mode 100644 index 000000000..bda552f00 --- /dev/null +++ b/packages/browser/test/functional/helpers/constants/configParts/thirdPartyCookiesEnabled.js @@ -0,0 +1,15 @@ +/* +Copyright 2020 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. +*/ + +export default { + thirdPartyCookiesEnabled: true, +}; diff --git a/packages/browser/test/functional/helpers/constants/consent.js b/packages/browser/test/functional/helpers/constants/consent.js new file mode 100644 index 000000000..d1a476329 --- /dev/null +++ b/packages/browser/test/functional/helpers/constants/consent.js @@ -0,0 +1,145 @@ +/* +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. +*/ +export const CONSENT_IN = { + consent: [ + { + standard: "Adobe", + version: "1.0", + value: { + general: "in", + }, + }, + ], +}; +export const CONSENT_OUT = { + consent: [ + { + standard: "Adobe", + version: "1.0", + value: { + general: "out", + }, + }, + ], +}; + +export const IAB_CONSENT_IN = { + consent: [ + { + standard: "IAB TCF", + version: "2.0", + value: "CO052l-O052l-DGAMBFRACBgAIBAAAAAAIYgEawAQEagAAAA", + gdprApplies: true, + }, + ], +}; + +export const IAB_CONSENT_IN_PERSONAL_DATA = { + consent: [ + { + standard: "IAB TCF", + version: "2.0", + value: "CO052l-O052l-DGAMBFRACBgAIBAAAAAAIYgEawAQEagAAAA", + gdprApplies: true, + gdprContainsPersonalData: true, + }, + ], +}; + +export const IAB_CONSENT_IN_NO_GDPR = { + consent: [ + { + standard: "IAB TCF", + version: "2.0", + value: "CO052l-O052l-DGAMBFRACBgAIBAAAAAAIYgEawAQEagAAAA", + gdprApplies: false, + }, + ], +}; + +export const IAB_NO_PURPOSE_ONE = { + consent: [ + { + standard: "IAB TCF", + version: "2.0", + value: "CO052oTO052oTDGAMBFRACBgAABAAAAAAIYgEawAQEagAAAA", + gdprApplies: true, + }, + ], +}; + +export const IAB_NO_PURPOSE_ONE_NO_GRPR = { + consent: [ + { + standard: "IAB TCF", + version: "2.0", + value: "CO052oTO052oTDGAMBFRACBgAABAAAAAAIYgEawAQEagAAAA", + gdprApplies: false, + }, + ], +}; + +export const IAB_NO_PURPOSE_TEN = { + consent: [ + { + standard: "IAB TCF", + version: "2.0", + value: "CO052kIO052kIDGAMBFRACBgAIAAAAAAAIYgEawAQEagAAAA", + gdprApplies: true, + }, + ], +}; + +export const IAB_NO_ADOBE_VENDOR = { + consent: [ + { + standard: "IAB TCF", + version: "2.0", + value: "CO052qdO052qdDGAMBFRACBgAIBAAAAAAIYgAAoAAAAA", + gdprApplies: true, + }, + ], +}; + +export const ADOBE2_IN = { + consent: [ + { + standard: "Adobe", + version: "2.0", + value: { + collect: { + val: "y", + }, + metadata: { + time: "2019-01-01T15:52:25+00:00", + }, + }, + }, + ], +}; + +export const ADOBE2_OUT = { + consent: [ + { + standard: "Adobe", + version: "2.0", + value: { + collect: { + val: "n", + }, + metadata: { + time: "2019-01-01T15:52:25+00:00", + }, + }, + }, + ], +}; diff --git a/packages/browser/test/functional/helpers/constants/cookies.js b/packages/browser/test/functional/helpers/constants/cookies.js new file mode 100644 index 000000000..a6274e704 --- /dev/null +++ b/packages/browser/test/functional/helpers/constants/cookies.js @@ -0,0 +1,21 @@ +/* +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. +*/ +export const MAIN_IDENTITY_COOKIE_NAME = + "kndctr_5BFE274A5F6980A50A495C08_AdobeOrg_identity"; +export const MAIN_CONSENT_COOKIE_NAME = + "kndctr_5BFE274A5F6980A50A495C08_AdobeOrg_consent"; +export const MAIN_CLUSTER_COOKIE_NAME = + "kndctr_5BFE274A5F6980A50A495C08_AdobeOrg_cluster"; +export const LEGACY_IDENTITY_COOKIE_NAME = + "AMCV_5BFE274A5F6980A50A495C08%40AdobeOrg"; +export const LEGACY_IDENTITY_COOKIE_UNESCAPED_NAME = + LEGACY_IDENTITY_COOKIE_NAME.replace("%40", "@"); diff --git a/packages/browser/test/functional/helpers/constants/datastreamId.js b/packages/browser/test/functional/helpers/constants/datastreamId.js new file mode 100644 index 000000000..669286658 --- /dev/null +++ b/packages/browser/test/functional/helpers/constants/datastreamId.js @@ -0,0 +1,12 @@ +/* +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. +*/ +export default "bc1a10e0-aee4-4e0e-ac5b-cdbb9abbec83"; diff --git a/packages/browser/test/functional/helpers/constants/deviceContextConfig.js b/packages/browser/test/functional/helpers/constants/deviceContextConfig.js new file mode 100644 index 000000000..443318f16 --- /dev/null +++ b/packages/browser/test/functional/helpers/constants/deviceContextConfig.js @@ -0,0 +1,17 @@ +/* +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 orgMainConfigMain from "./configParts/orgMainConfigMain.js"; + +export default { + context: ["device"], + ...orgMainConfigMain, +}; diff --git a/packages/browser/test/functional/helpers/constants/domain.js b/packages/browser/test/functional/helpers/constants/domain.js new file mode 100644 index 000000000..10d6ad15f --- /dev/null +++ b/packages/browser/test/functional/helpers/constants/domain.js @@ -0,0 +1,14 @@ +/* +Copyright 2020 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. +*/ + +export const THIRD_PARTY_DOMAIN = "edge.adobedc.net"; +export const FIRST_PARTY_DOMAIN = "firstparty.alloyio.com"; diff --git a/packages/browser/test/functional/helpers/constants/environmentContextConfig.js b/packages/browser/test/functional/helpers/constants/environmentContextConfig.js new file mode 100644 index 000000000..ff3d845eb --- /dev/null +++ b/packages/browser/test/functional/helpers/constants/environmentContextConfig.js @@ -0,0 +1,17 @@ +/* +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 orgMainConfigMain from "./configParts/orgMainConfigMain.js"; + +export default { + context: ["environment"], + ...orgMainConfigMain, +}; diff --git a/packages/browser/test/functional/helpers/constants/highEntropyUserAgentHintsContextConfig.js b/packages/browser/test/functional/helpers/constants/highEntropyUserAgentHintsContextConfig.js new file mode 100644 index 000000000..562e5ccec --- /dev/null +++ b/packages/browser/test/functional/helpers/constants/highEntropyUserAgentHintsContextConfig.js @@ -0,0 +1,17 @@ +/* +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 orgMainConfigMain from "./configParts/orgMainConfigMain.js"; + +export default { + context: ["highEntropyUserAgentHints"], + ...orgMainConfigMain, +}; diff --git a/packages/browser/test/functional/helpers/constants/placeContextConfig.js b/packages/browser/test/functional/helpers/constants/placeContextConfig.js new file mode 100644 index 000000000..a444a84c9 --- /dev/null +++ b/packages/browser/test/functional/helpers/constants/placeContextConfig.js @@ -0,0 +1,17 @@ +/* +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 orgMainConfigMain from "./configParts/orgMainConfigMain.js"; + +export default { + context: ["placeContext"], + ...orgMainConfigMain, +}; diff --git a/packages/browser/test/functional/helpers/constants/regex.js b/packages/browser/test/functional/helpers/constants/regex.js new file mode 100644 index 000000000..822c1596f --- /dev/null +++ b/packages/browser/test/functional/helpers/constants/regex.js @@ -0,0 +1,13 @@ +/* +Copyright 2021 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. +*/ + +export const ECID = /^[0-9]{38}$/; diff --git a/packages/browser/test/functional/helpers/constants/remoteVisitorLibraryUrl.js b/packages/browser/test/functional/helpers/constants/remoteVisitorLibraryUrl.js new file mode 100644 index 000000000..10870ed3c --- /dev/null +++ b/packages/browser/test/functional/helpers/constants/remoteVisitorLibraryUrl.js @@ -0,0 +1,13 @@ +/* +Copyright 2020 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. +*/ + +export default "https://github.com/Adobe-Marketing-Cloud/id-service/releases/latest/download/visitorapi.min.js"; diff --git a/packages/browser/test/functional/helpers/constants/url.js b/packages/browser/test/functional/helpers/constants/url.js new file mode 100644 index 000000000..81f53b649 --- /dev/null +++ b/packages/browser/test/functional/helpers/constants/url.js @@ -0,0 +1,24 @@ +/* +Copyright 2021 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. +*/ + +const baseUrl = `https://alloyio.com/functional-test`; + +export const TEST_PAGE = `${baseUrl}/testPage.html`; +export const TEST_PAGE_AT_JS_TWO = `${baseUrl}/testPageWithAtjs2.html`; +export const TEST_PAGE_AT_JS_ONE = `${baseUrl}/testPageWithAtjs1.html`; +export const TEST_PAGE_WITH_CSP = `${baseUrl}/testPageWithCsp.html`; +// This page is only used by reloadPage.js as an interim workaround for +// https://github.com/DevExpress/testcafe/issues/5992 +export const RELOAD_PAGE = `${baseUrl}/reloadPage.html`; + +const secondaryBaseUrl = `https://alloyio2.com/functional-test`; +export const SECONDARY_TEST_PAGE = `${secondaryBaseUrl}/testPage.html`; diff --git a/packages/browser/test/functional/helpers/constants/webContextConfig.js b/packages/browser/test/functional/helpers/constants/webContextConfig.js new file mode 100644 index 000000000..61bd1d3e4 --- /dev/null +++ b/packages/browser/test/functional/helpers/constants/webContextConfig.js @@ -0,0 +1,17 @@ +/* +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 orgMainConfigMain from "./configParts/orgMainConfigMain.js"; + +export default { + context: ["web"], + ...orgMainConfigMain, +}; diff --git a/packages/browser/test/functional/helpers/cookies.js b/packages/browser/test/functional/helpers/cookies.js new file mode 100644 index 000000000..aeabd22c8 --- /dev/null +++ b/packages/browser/test/functional/helpers/cookies.js @@ -0,0 +1,57 @@ +/* +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 { ClientFunction, t } from "testcafe"; + +const blankOutCookieInBrowser = ClientFunction((name) => { + document.cookie = `${name}=;expires=Thu, 01 Jan 1970 00:00:00 GMT`; +}); + +export default { + clear: ClientFunction(() => { + const cookies = document.cookie.split(";"); + + for (let i = 0; i < cookies.length; i += 1) { + const cookie = cookies[i]; + const eqPos = cookie.indexOf("="); + const name = eqPos > -1 ? cookie.substr(0, eqPos) : cookie; + document.cookie = `${name}=;expires=Thu, 01 Jan 1970 00:00:00 GMT`; + } + }), + get: ClientFunction((name) => { + const cookies = document.cookie + .split(";") + .map((c) => { + const ct = c.trim(); + const index = ct.indexOf("="); + return [ct.slice(0, index), ct.slice(index + 1)].map( + decodeURIComponent, + ); + }) + .reduce((a, b) => { + try { + a[b[0]] = JSON.parse(b[1]); + } catch { + a[b[0]] = b[1]; + } + return a; + }, {}); + + return cookies[name] || undefined; + }), + async remove(name) { + // From testing, I noticed that Web SDK no longer has access to the cookies + // when we use cookies.remove, and the browser no longer has access to the cookies + // when we use t.deleteCookies. So I call both here. + await blankOutCookieInBrowser(name); + await t.deleteCookies(name); + }, +}; diff --git a/packages/browser/test/functional/helpers/createAdobeMC.js b/packages/browser/test/functional/helpers/createAdobeMC.js new file mode 100644 index 000000000..e5e5d0375 --- /dev/null +++ b/packages/browser/test/functional/helpers/createAdobeMC.js @@ -0,0 +1,22 @@ +/* +Copyright 2022 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 createRandomEcid from "./createRandomEcid.js"; +import { orgMainConfigMain } from "./constants/configParts/index.js"; + +export default ({ timestamp, id, orgId } = {}) => { + const ts = timestamp || new Date().getTime() / 1000; + const mcmid = id || createRandomEcid(); + const mcorgid = orgId || orgMainConfigMain.orgId; + + return encodeURIComponent(`TS=${ts}|MCMID=${mcmid}|MCORGID=${mcorgid}`); +}; diff --git a/packages/browser/test/functional/helpers/createAlloyProxy.js b/packages/browser/test/functional/helpers/createAlloyProxy.js new file mode 100644 index 000000000..3994ae235 --- /dev/null +++ b/packages/browser/test/functional/helpers/createAlloyProxy.js @@ -0,0 +1,124 @@ +/* + * Using TestCafe, the test code is run inside Node. If you want to run code inside the browser + * you have to use ClientFunctions or t.eval. TestCafe compiles and copies the code inside the + * ClientFunction or eval onto the browser page and then runs it. TestCafe also has a system for + * taking the return value and bringing (marshalling) it into Node. + * + * There are a few gotchas when using ClientFunction and t.eval with promises. First, promises are + * only marshalled when they are the only thing returned from the client function. If a promise is + * included as part of a returned object, the promise isn't marshalled correctly. Secondly, if you + * do not `await` the ClientFunction execution in the test, client functions may be executed out + * of order. Lastly, if an error is thrown on the browser inside the returned promise, the error is + * wrapped in a TestCafe error object. It is easier to get the error information if you catch the + * error inside the browser. Using this Alloy proxy avoids these pitfalls. + * + * To create a proxy, call the default export of this file like this: + * + * const alloy = createAlloyProxy(); + * + * You can pass in the name of the Alloy global variable if needed (it defaults to "alloy".) + * + * const instance2 = createAlloyProxy("instance2"); + * + * All the Alloy commands are implemented as methods on the returned proxy object. They return a + * marshalled promise from the Alloy command. Be sure to always use "await" when calling any method + * on the proxy. + * + * await alloy.configure(config); + * await alloy.sendEvent({ renderDecisions: true }); + * + * Additionally each command has a xxxErrorMessage variant that returns a promise that will resolve + * with undefined if there was no error, and the error message if there was an error. + * + * const errorMessage = await alloy.sendEventErrorMessage(); + * await t.expect(errorMessage).ok("Expected an error, but didn't get one"); + * await t.expect(errorMessage).contains("myerror"); + * + * Sometimes in a test you need to run other commands before a command finishes. For example, sending an + * event may not resolve until after consent is given. For these cases, each command has a xxxAsync variant + * that returns an object with two promises: "result", and "errorMessage". Both of these promises resolve + * when the command is finished. "result" will resolve to the result of the command, and errorMessage will + * resolve with undefined if there was no error, and the error message if there was an error. + * + * const sendEventResponse = await alloy.sendEventAsync(); + * await alloy.setConsent(...); + * await sendEventResponse.result; + * + */ +import { ClientFunction } from "testcafe"; + +const proxyFunction = ClientFunction((instanceName, command, options) => { + // return the promise from the client function + return window[instanceName](command, options); +}); + +const asyncProxyFunction = ClientFunction((instanceName, command, options) => { + // save the promise to a browser global variable to be referenced later + window.lastAlloyProxyPromise = window[instanceName](command, options); +}); + +const errorMessageProxyFunction = ClientFunction( + (instanceName, command, options) => { + // return a promise that resolves to the error message or undefined + return window[instanceName](command, options).then( + () => undefined, + (e) => e.message, + ); + }, +); + +const getLastPromise = ClientFunction(() => { + // fetch the last promise set by asyncProxyFunction + return window.lastAlloyProxyPromise; +}); + +const getLastErrorMessage = ClientFunction(() => { + // return a promise that resolves to the error message or undefined + // using the last promise set by asyncProxyFunction + return window.lastAlloyProxyPromise.then( + () => undefined, + (e) => e.message, + ); +}); + +const commands = [ + "configure", + "sendEvent", + "applyResponse", + "setConsent", + "getIdentity", + "setDebug", + "getLibraryInfo", + "appendIdentityToUrl", + "applyPropositions", + "subscribeRulesetItems", + "evaluateRulesets", + "createMediaSession", + "sendMediaEvent", + "getMediaAnalyticsTracker", +]; + +export default (instanceName = "alloy") => { + const proxy = {}; + commands.forEach((command) => { + // Run the command and return the result. + proxy[command] = (options) => proxyFunction(instanceName, command, options); + + // Run the command and return the error message or undefined. + proxy[`${command}ErrorMessage`] = (options) => + errorMessageProxyFunction(instanceName, command, options); + + // Run the command, but don't wait on the result. + proxy[`${command}Async`] = async (options) => { + // This command calls three separate ClientFunctions to get three promises: + // 1. We await on the TestCafe generated promise from running the client function. + // This ensures that commands are run in order + // 2. We get the promise from the command that will resolve to the result. + // 3. We get the error message from the command if there is one. + await asyncProxyFunction(instanceName, command, options); + return { result: getLastPromise(), errorMessage: getLastErrorMessage() }; + }; + }); + + return proxy; +}; diff --git a/packages/browser/test/functional/helpers/createCollectEndpointAsserter.js b/packages/browser/test/functional/helpers/createCollectEndpointAsserter.js new file mode 100644 index 000000000..4b8b5abb4 --- /dev/null +++ b/packages/browser/test/functional/helpers/createCollectEndpointAsserter.js @@ -0,0 +1,120 @@ +/* +Copyright 2021 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 } from "testcafe"; +import createNetworkLogger from "./networkLogger/index.js"; +import sendBeaconMock from "./sendBeaconMock.js"; + +/** + * A useful utility when dealing with assertions related to + * the collect endpoint. Alloy sends requests to the collect endpoint + * using sendBeacon if sendBeacon is supported by the browser. When + * sendBeacon is called, the browser doesn't send the request right + * away, but instead queues the request to be sent sometime + * later, which can make it tricky to correctly assert that requests + * have or have not been sent to the endpoint. + */ +export default async () => { + const networkLogger = createNetworkLogger(); + await t.addRequestHooks( + networkLogger.edgeInteractEndpointLogs, + networkLogger.edgeCollectEndpointLogs, + ); + + await sendBeaconMock.mock(); + const assertCollectCalled = async () => { + // When sendBeacon is called, the browser doesn't send the request right away, + // but instead queues the request to be sent sometime later. Therefore, the + // sendEvent promise resolves before any network request may have actually been made. + // By calling the RequestLogger's count method, TestCafe will retry this + // assertion until it succeeds or until the timeout is reached. The parameter + // to count is a filter function. In this case, we want to count all the requests. + await t + .expect(networkLogger.edgeCollectEndpointLogs.count(() => true)) + .eql(1, "No network request to the collect endpoint was detected."); + // If sendBeacon is supported by the browser, we should always be using it when + // sending requests to the collect endpoint. + await t + .expect(sendBeaconMock.getCallCount()) + .eql(1, "No sendBeacon call was detected."); + }; + + const assertCollectNotCalled = async () => { + // When sendBeacon is called, the browser doesn't send the request right away, + // but instead queues the request to be sent sometime later. Therefore, the + // sendEvent promise resolves before any network request may have actually been made. + // In order to check that a request to the collect endpoint is never made, we would + // have to wait for an arbitrary period of time before checking that the number of + // network requests to the collect endpoint is 0. Instead of waiting for an arbitrary + // period of time, which is a fragile and slow solution, we'll make our best attempt + // at this assertion by checking that sendBeacon was never called. If supported by the + // browser, sendBeacon is solely used to send requests to collect, so it's a fair approximation. + await t + .expect(sendBeaconMock.getCallCount()) + .eql(0, "A network request to the collect endpoint was detected."); + }; + + const assertInteractCalled = async () => { + await t + .expect(networkLogger.edgeInteractEndpointLogs.requests.length) + .eql(1, "No network request to the interact endpoint was detected."); + }; + + const assertInteractNotCalled = async () => { + await t + .expect(networkLogger.edgeInteractEndpointLogs.requests.length) + .eql(0, "A network request to the interact endpoint was detected."); + }; + + let collectRequestAsserted = false; + let interactRequestAsserted = false; + return { + async assertCollectCalledAndNotInteract() { + collectRequestAsserted = true; + // The order of these matter because we need to make sure sendBeacon + // requests have actually been sent by the browser before checking + // that they weren't interact calls. + await assertCollectCalled(); + await assertInteractNotCalled(); + }, + async assertInteractCalledAndNotCollect() { + interactRequestAsserted = true; + await assertCollectNotCalled(); + await assertInteractCalled(); + }, + async assertNeitherCollectNorInteractCalled() { + await assertCollectNotCalled(); + await assertInteractNotCalled(); + }, + async reset() { + interactRequestAsserted = false; + collectRequestAsserted = false; + await networkLogger.clearLogs(); + await sendBeaconMock.reset(); + }, + getInteractRequest() { + if (!interactRequestAsserted) { + throw new Error( + "You must call assertInteractCalledAndNotCollect before getting the interact request", + ); + } + return networkLogger.edgeInteractEndpointLogs.requests[0]; + }, + getCollectRequest() { + if (!collectRequestAsserted) { + throw new Error( + "You must call assertCollectCalledAndNotInteract before getting the collect request", + ); + } + return networkLogger.edgeCollectEndpointLogs.requests[0]; + }, + }; +}; diff --git a/packages/browser/test/functional/helpers/createFixture/clientScripts.js b/packages/browser/test/functional/helpers/createFixture/clientScripts.js new file mode 100644 index 000000000..2576bbda8 --- /dev/null +++ b/packages/browser/test/functional/helpers/createFixture/clientScripts.js @@ -0,0 +1,223 @@ +/* +Copyright 2020 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 path from "path"; +import fs from "fs"; +import readCache from "read-cache"; +import { ClientFunction } from "testcafe"; +import { INTEGRATION, PRODUCTION } from "../constants/alloyEnvironment.js"; +import REMOTE_VISITOR_LIBRARY_URL from "../constants/remoteVisitorLibraryUrl.js"; + +const alloyEnv = process.env.ALLOY_ENV || INTEGRATION; +const alloyProdVersion = process.env.ALLOY_PROD_VERSION; +// eslint-disable-next-line no-console +console.log(`ALLOY ENV: ${alloyEnv}`); + +if (alloyEnv === PRODUCTION) { + if (alloyProdVersion) { + // eslint-disable-next-line no-console + console.log(`ALLOY PROD VERSION: ${alloyProdVersion}`); + } else { + throw new Error( + "The ALLOY_PROD_VERSION environment variable must be provided when running against the production environment.", + ); + } +} +const rootDir = path.join(__dirname, "../../../../"); +const baseCodePath = path.join(rootDir, "distTest/baseCode.min.js"); +const localAlloyLibraryPath = path.join(rootDir, "dist/alloy.js"); +const localNpmLibraryPath = path.join(rootDir, "distTest/npmPackageLocal.js"); +const prodNpmLibraryPath = path.join(rootDir, "distTest/npmPackageProd.js"); +const remoteAlloyLibraryUrl = `https://cdn1.adoberesources.net/alloy/${alloyProdVersion}/alloy.js`; + +// We use this getter for retrieving the library code instead of just loading +// the library code a single time up-front, because we want every run to be +// using the latest library code. This is important when developing in watch +// mode and making changes to source files. +const getLocalAlloyCode = () => + // readCache caches file content until the file is modified, at which + // point it will retrieve fresh file content, cache it, and return it. + readCache.sync(localAlloyLibraryPath, "utf8"); +// This is the javascript built from src/index.js which does not include the +// baseCode, but exposes a createInstance function. +const getLocalNpmLibraryCode = () => + readCache.sync(localNpmLibraryPath, "utf8"); +// This is the javascript built from the production @adobe/alloy npm Library +const getProdNpmLibraryCode = () => readCache.sync(prodNpmLibraryPath, "utf8"); + +export const injectInlineScript = ClientFunction((code) => { + const scriptElement = document.createElement("script"); + + scriptElement.innerHTML = code; + document.getElementsByTagName("head")[0].appendChild(scriptElement); +}); + +const baseCodeWithCustomInstances = fs + .readFileSync(baseCodePath, "utf8") + .replace('["alloy"]', '["alloy","instance2"]'); + +const addRemoteUrlClientScript = ({ clientScripts, url, async = false }) => { + // TestCafe client scripts don't "natively" support loading a script + // from a remote URL, so we have to make our local script add another script + // element that loads Visitor from the remote server. + clientScripts.push({ + content: `document.write('')`, + }); +}; + +/** + * Produces an array of scripts that TestCafe should inject into the + * when testing Alloy int. + */ +const getFixtureClientScriptsForInt = (options) => { + const clientScripts = []; + + if (options.monitoringHooksScript) { + clientScripts.push({ + content: options.monitoringHooksScript, + }); + } + + // Useful for testing Alloy + Visitor interaction. + if (options.includeVisitorLibrary) { + addRemoteUrlClientScript({ + clientScripts, + url: REMOTE_VISITOR_LIBRARY_URL, + }); + } + + clientScripts.push({ + content: baseCodeWithCustomInstances, + }); + + // Typically the Alloy library should be loaded in head. For some tests, + // like testing command queuing, we need greater control and will + // load the Alloy library later during the test using injectAlloyDuringTest. + if (options.includeAlloyLibrary) { + // When providing client scripts to TestCafe during the fixture + // configuration process, TestCafe doesn't currently support loading scripts + // asynchronously (https://github.com/DevExpress/testcafe/issues/5612), but + // by default our customers are loading Alloy asynchronously and we would + // like to simulate that. To do so, we'll wrap our Alloy code in a + // setTimeout with a small arbitrary delay. + clientScripts.push({ + content: `setTimeout(function() {\n${getLocalAlloyCode()}\n}, 10);`, + }); + } + + if (options.includeNpmLibrary) { + clientScripts.push({ + content: getLocalNpmLibraryCode(), + }); + } + + return clientScripts; +}; + +/** + * Produces an array of scripts that TestCafe should inject into the + * when testing Alloy prod. + */ +const getFixtureClientScriptsForProd = (options) => { + const clientScripts = []; + + if (options.monitoringHooksScript) { + clientScripts.push({ + content: options.monitoringHooksScript, + }); + } + + // Useful for testing Alloy + Visitor interaction. + if (options.includeVisitorLibrary) { + addRemoteUrlClientScript({ + clientScripts, + url: REMOTE_VISITOR_LIBRARY_URL, + }); + } + + clientScripts.push({ + content: baseCodeWithCustomInstances, + }); + + // Typically the Alloy library should be loaded in head. For some tests, + // like testing command queuing, we need greater control and will + // load the Alloy library later during the test using injectAlloyDuringTest. + if (options.includeAlloyLibrary) { + addRemoteUrlClientScript({ + clientScripts, + url: remoteAlloyLibraryUrl, + async: true, + }); + } + + if (options.includeNpmLibrary) { + clientScripts.push({ + content: getProdNpmLibraryCode(), + }); + } + return clientScripts; +}; + +const getFixtureClientScriptsByEnvironment = { + int: getFixtureClientScriptsForInt, + prod: getFixtureClientScriptsForProd, +}; + +/** + * Injects Alloy into the page while running a test against Alloy int. + */ +const injectAlloyDuringTestForInt = () => + injectInlineScript(getLocalAlloyCode()); + +/** + * Injects Alloy into the page while running a test against Alloy prod. + */ +const injectAlloyDuringTestForProd = ClientFunction( + () => + new Promise((resolve) => { + const scriptElement = document.createElement("script"); + scriptElement.src = remoteAlloyLibraryUrl; + scriptElement.addEventListener("load", () => { + resolve(); + }); + document.getElementsByTagName("head")[0].appendChild(scriptElement); + }), + { + dependencies: { + remoteAlloyLibraryUrl, + }, + }, +); + +const injectAlloyDuringTestByEnvironment = { + [INTEGRATION]: injectAlloyDuringTestForInt, + [PRODUCTION]: injectAlloyDuringTestForProd, +}; + +/** + * Retrieves a clientScripts array that can be provided to a TestCafe fixture, + * which will inject script tags into the of the test page. + */ +export const getFixtureClientScripts = + getFixtureClientScriptsByEnvironment[alloyEnv]; + +/** + * Injects the Alloy library while a test is running. This is useful if you + * want to test what happens when, for example, commands are queued before + * the Alloy library finishes loading. If you use this, you'll want to set + * includeAlloyLibrary to false when configuring client scripts for the + * fixture so that Alloy isn't injected into . + */ +export const injectAlloyDuringTest = + injectAlloyDuringTestByEnvironment[alloyEnv]; diff --git a/packages/browser/test/functional/helpers/createFixture/destinationRequestMock.js b/packages/browser/test/functional/helpers/createFixture/destinationRequestMock.js new file mode 100644 index 000000000..ecf569f60 --- /dev/null +++ b/packages/browser/test/functional/helpers/createFixture/destinationRequestMock.js @@ -0,0 +1,23 @@ +/* +Copyright 2021 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 { RequestMock } from "testcafe"; + +// The main edge configuration we're using for testing +// has URL destinations enabled and a URL destination handle is sent +// back as part of the response from each interact endpoint request. +// So that we're not relying on a third-party server for the URL +// destination to successfully execute, we'll mock the third-party +// URL destination endpoint. +export default RequestMock() + .onRequestTo(/^https:\/\/cataas.com\//) + .respond(null, 200); diff --git a/packages/browser/test/functional/helpers/createFixture/index.js b/packages/browser/test/functional/helpers/createFixture/index.js new file mode 100644 index 000000000..b5bde7d03 --- /dev/null +++ b/packages/browser/test/functional/helpers/createFixture/index.js @@ -0,0 +1,35 @@ +/* +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 { TEST_PAGE as TEST_PAGE_URL } from "../constants/url.js"; +import { getFixtureClientScripts } from "./clientScripts.js"; +import destinationRequestMock from "./destinationRequestMock.js"; + +export default ({ + title = "", + url = TEST_PAGE_URL, + requestHooks = [], + monitoringHooksScript, + includeAlloyLibrary = true, + includeVisitorLibrary = false, + includeNpmLibrary = false, +}) => { + const clientScripts = getFixtureClientScripts({ + monitoringHooksScript, + includeAlloyLibrary, + includeVisitorLibrary, + includeNpmLibrary, + }); + return fixture(title) + .page(url) + .requestHooks(...requestHooks, destinationRequestMock) + .clientScripts(clientScripts); +}; diff --git a/packages/browser/test/functional/helpers/createRandomEcid.js b/packages/browser/test/functional/helpers/createRandomEcid.js new file mode 100644 index 000000000..54e9da767 --- /dev/null +++ b/packages/browser/test/functional/helpers/createRandomEcid.js @@ -0,0 +1,24 @@ +/* +Copyright 2022 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 crypto from "crypto"; + +// 2 random 63 bit numbers padded with zeros to 19 digits and concatenated +export default () => { + const randomBytesBuffer = crypto.randomBytes(16); + // eslint-disable-next-line no-bitwise + randomBytesBuffer[0] &= 0x7f; + // eslint-disable-next-line no-bitwise + randomBytesBuffer[8] &= 0x7f; + const high = randomBytesBuffer.readBigInt64BE(0).toString(); + const low = randomBytesBuffer.readBigInt64BE(8).toString(); + return high.padStart(19, "0") + low.padStart(19, "0"); +}; diff --git a/packages/browser/test/functional/helpers/createResponse.js b/packages/browser/test/functional/helpers/createResponse.js new file mode 100644 index 000000000..d6e07623a --- /dev/null +++ b/packages/browser/test/functional/helpers/createResponse.js @@ -0,0 +1,15 @@ +/* +Copyright 2021 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 injectCreateResponse from "../../../../core/src/core/injectCreateResponse.js"; + +export default injectCreateResponse({ logger: console }); diff --git a/packages/browser/test/functional/helpers/createUnhandledRejectionLogger.js b/packages/browser/test/functional/helpers/createUnhandledRejectionLogger.js new file mode 100644 index 000000000..0947fcec5 --- /dev/null +++ b/packages/browser/test/functional/helpers/createUnhandledRejectionLogger.js @@ -0,0 +1,83 @@ +/* +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 } from "testcafe"; + +const containsMessageMatchingRegex = (messages, messageRegex) => { + return messages.find((message) => messageRegex.test(message)) !== undefined; +}; + +const formatFoundMessages = (messages) => { + if (!messages.length) { + return "No messages found."; + } + return `Messages found:\n${messages.join("\n")}`; +}; + +/** + * Creates an object that can used for asserting messages from unhandled + * rejections. These are promises that were rejected, but unhandled. + * + * Example: + * + * const unhandledRejectionLogger = await createUnhandledRejectionLogger(); + * await unhandledRejectionLogger.expectMessageMatching(/test/); + * await unhandledRejectionLogger.expectNoMessageMatching(/test/); + * await unhandledRejectionLogger.reset(); + */ +export default async () => { + await t.eval(() => { + window.testcafe_unhandled_rejections = []; + window.addEventListener("unhandledrejection", ({ reason }) => { + window.testcafe_unhandled_rejections.push(reason); + }); + }); + + const reset = async () => { + await t.eval(() => { + window.testcafe_unhandled_rejections.clear(); + }); + }; + + const getMessagesSinceReset = async () => { + return t.eval(() => { + return window.testcafe_unhandled_rejections || []; + }); + }; + + const expectMessageMatching = async (messageRegex) => { + const messages = await getMessagesSinceReset(); + await t + .expect(containsMessageMatchingRegex(messages, messageRegex)) + .ok( + `No unhandled rejection message was found matching ${messageRegex}. ${formatFoundMessages( + messages, + )}`, + ); + }; + + const expectNoMessageMatching = async (messageRegex) => { + const messages = await getMessagesSinceReset(); + await t + .expect(containsMessageMatchingRegex(messages, messageRegex)) + .notOk( + `An unhandled rejection message was found matching ${messageRegex} when none was expected. ${formatFoundMessages( + messages, + )}`, + ); + }; + + return { + reset, + expectMessageMatching, + expectNoMessageMatching, + }; +}; diff --git a/packages/browser/test/functional/helpers/dom/addHtmlToBody.js b/packages/browser/test/functional/helpers/dom/addHtmlToBody.js new file mode 100644 index 000000000..74d87337d --- /dev/null +++ b/packages/browser/test/functional/helpers/dom/addHtmlToBody.js @@ -0,0 +1,25 @@ +/* +Copyright 2020 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 { ClientFunction } from "testcafe"; + +export default ClientFunction((html, replace = false) => { + if (replace) { + document.body.innerHTML = ""; + } + + const div = document.createElement("div"); + div.innerHTML = html; + while (div.firstChild) { + document.body.appendChild(div.firstChild); + } +}); diff --git a/packages/browser/test/functional/helpers/dom/addHtmlToHeader.js b/packages/browser/test/functional/helpers/dom/addHtmlToHeader.js new file mode 100644 index 000000000..19579c1c8 --- /dev/null +++ b/packages/browser/test/functional/helpers/dom/addHtmlToHeader.js @@ -0,0 +1,20 @@ +/* +Copyright 2020 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 { ClientFunction } from "testcafe"; + +export default ClientFunction((html) => { + const head = document.createElement("head"); + head.innerHTML = html; + while (head.firstChild) { + document.head.appendChild(head.firstChild); + } +}); diff --git a/packages/browser/test/functional/helpers/flushPromiseChains.js b/packages/browser/test/functional/helpers/flushPromiseChains.js new file mode 100644 index 000000000..203292e34 --- /dev/null +++ b/packages/browser/test/functional/helpers/flushPromiseChains.js @@ -0,0 +1,32 @@ +/* +Copyright 2019 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 { ClientFunction } from "testcafe"; + +/** + * Returns a promise that will be resolved after all outstanding promise chains + * have been flushed. This assumes (1) that the promise chains to be flushed + * resolve their promises promptly (rather than doing something like + * setTimeout(..., 100) somewhere in the chain) and (2) that the chains + * are no longer than 10 promises long. + * @returns {Promise} + */ +export default ClientFunction(() => { + let promise; + + for (let i = 0; i < 10; i += 1) { + promise = promise + ? promise.then(() => Promise.resolve()) + : Promise.resolve(); + } + + return promise; +}); diff --git a/packages/browser/test/functional/helpers/getBaseConfig.js b/packages/browser/test/functional/helpers/getBaseConfig.js new file mode 100644 index 000000000..6073ee065 --- /dev/null +++ b/packages/browser/test/functional/helpers/getBaseConfig.js @@ -0,0 +1,30 @@ +/* +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 DATASTREAM_ID from "./constants/datastreamId.js"; +import edgeDomainThirdParty from "./constants/configParts/edgeDomainThirdParty.js"; + +const edgeBasePath = process.env.EDGE_BASE_PATH; + +export default (orgId, configId = DATASTREAM_ID) => { + const config = { + datastreamId: configId, + orgId: orgId || "5BFE274A5F6980A50A495C08@AdobeOrg", + // Default `edgeDomain` to 3rd party; override in specific test if needed. + ...edgeDomainThirdParty, + }; + + if (edgeBasePath) { + config.edgeBasePath = edgeBasePath; + } + + return config; +}; diff --git a/packages/browser/test/functional/helpers/isUserAgentClientHintsSupported.js b/packages/browser/test/functional/helpers/isUserAgentClientHintsSupported.js new file mode 100644 index 000000000..0002cae97 --- /dev/null +++ b/packages/browser/test/functional/helpers/isUserAgentClientHintsSupported.js @@ -0,0 +1,15 @@ +/* +Copyright 2022 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 { ClientFunction } from "testcafe"; + +export default ClientFunction(() => "userAgentData" in navigator); diff --git a/packages/browser/test/functional/helpers/networkLogger/awaitRequestResponse.js b/packages/browser/test/functional/helpers/networkLogger/awaitRequestResponse.js new file mode 100644 index 000000000..70e05b1da --- /dev/null +++ b/packages/browser/test/functional/helpers/networkLogger/awaitRequestResponse.js @@ -0,0 +1,21 @@ +/* +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. +*/ + +export default async (request) => + new Promise((r) => { + const t = setInterval(() => { + if (request.response) { + clearInterval(t); + r(); + } + }, 10); + }); diff --git a/packages/browser/test/functional/helpers/networkLogger/getResponseBody.js b/packages/browser/test/functional/helpers/networkLogger/getResponseBody.js new file mode 100644 index 000000000..ad0751603 --- /dev/null +++ b/packages/browser/test/functional/helpers/networkLogger/getResponseBody.js @@ -0,0 +1,38 @@ +/* +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. +*/ + +const zlib = require("zlib"); + +const getResponseBody = (request) => { + const encoding = request.response.headers["content-encoding"]; + const bodyBuffer = request.response.body; + let decompressedBody = bodyBuffer; + + // Chrome responses are getting here already decompressed. + // For Firefox, we need to decompress the body. + try { + // eslint-disable-next-line default-case + switch (encoding) { + case "deflate": + decompressedBody = zlib.inflateRawSync(bodyBuffer); + break; + case "gzip": + decompressedBody = zlib.gunzipSync(bodyBuffer); + break; + } + // eslint-disable-next-line no-empty + } catch {} + + return decompressedBody.toString(); +}; + +export default getResponseBody; diff --git a/packages/browser/test/functional/helpers/networkLogger/getReturnedEcid.js b/packages/browser/test/functional/helpers/networkLogger/getReturnedEcid.js new file mode 100644 index 000000000..8cb715040 --- /dev/null +++ b/packages/browser/test/functional/helpers/networkLogger/getReturnedEcid.js @@ -0,0 +1,26 @@ +/* +Copyright 2022 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 getResponseBody from "./getResponseBody.js"; +import createResponse from "../createResponse.js"; + +export default (request) => { + const response = JSON.parse(getResponseBody(request)); + const payloads = createResponse({ content: response }).getPayloadsByType( + "identity:result", + ); + const ecidPayload = payloads.filter( + (payload) => payload.namespace.code === "ECID", + )[0]; + + return ecidPayload.id; +}; diff --git a/packages/browser/test/functional/helpers/networkLogger/index.js b/packages/browser/test/functional/helpers/networkLogger/index.js new file mode 100644 index 000000000..1252e42f2 --- /dev/null +++ b/packages/browser/test/functional/helpers/networkLogger/index.js @@ -0,0 +1,148 @@ +/* +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 { RequestLogger } from "testcafe"; + +const networkLoggerOptions = { + logRequestHeaders: true, + logRequestBody: true, + logResponseBody: true, + stringifyResponseBody: false, + stringifyRequestBody: true, + logResponseHeaders: true, +}; + +const createRequestLogger = (endpoint) => { + return RequestLogger(endpoint, networkLoggerOptions); +}; + +const createNetworkLogger = () => { + const edgeEndpoint = /v1\/(interact|collect)\?configId=/; + const edgeCollectEndpoint = /v1\/collect\?configId=/; + const edgeInteractEndpoint = /v1\/interact\?configId=/; + const setConsentEndpoint = /v1\/privacy\/set-consent\?configId=/; + const acquireEndpoint = /v1\/identity\/acquire\?configId=/; + const targetDeliveryEndpoint = /rest\/v1\/delivery\?client=/; + const targetMboxJsonEndpoint = /m2\/unifiedjsqeonly\/mbox\/json\?mbox=/; + // media endpoints + const playEndpoint = /va\/v1\/play/; + const pauseEndpoint = /va\/v1\/pauseStart/; + const pingEndpoint = /va\/v1\/ping/; + const adBreakCompleteEndpoint = /va\/v1\/adBreakComplete/; + const adBreakStartEndpoint = /va\/v1\/adBreakStart/; + const adCompleteEndpoint = /va\/v1\/adComplete/; + const adSkipEndpoint = /va\/v1\/adSkip/; + const adStartEndpoint = /va\/v1\/adStart/; + const bitrateChangeEndpoint = /va\/v1\/bitrateChange/; + const bufferStartEndpoint = /va\/v1\/bufferStart/; + const chapterCompleteEndpoint = /va\/v1\/chapterComplete/; + const chapterSkipEndpoint = /va\/v1\/chapterSkip/; + const chapterStartEndpoint = /va\/v1\/chapterStart/; + const errorEndpoint = /va\/v1\/error/; + const sessionCompleteEndpoint = /va\/v1\/sessionComplete/; + const sessionEndEndpoint = /va\/v1\/sessionEnd/; + const statesUpdateEndpoint = /va\/v1\/statesUpdate/; + + const edgeEndpointLogs = createRequestLogger(edgeEndpoint); + const edgeCollectEndpointLogs = createRequestLogger(edgeCollectEndpoint); + const edgeInteractEndpointLogs = createRequestLogger(edgeInteractEndpoint); + const setConsentEndpointLogs = createRequestLogger(setConsentEndpoint); + const acquireEndpointLogs = createRequestLogger(acquireEndpoint); + const targetDeliveryEndpointLogs = createRequestLogger( + targetDeliveryEndpoint, + ); + const targetMboxJsonEndpointLogs = createRequestLogger( + targetMboxJsonEndpoint, + ); + // media endpoint loggers + const mediaPlayEndpointLogs = createRequestLogger(playEndpoint); + const mediaPauseEndpointLogs = createRequestLogger(pauseEndpoint); + const pingEndpointLogs = createRequestLogger(pingEndpoint); + const adBreakCompleteEndpointLogs = createRequestLogger( + adBreakCompleteEndpoint, + ); + const adBreakStartEndpointLogs = createRequestLogger(adBreakStartEndpoint); + const adCompleteEndpointLogs = createRequestLogger(adCompleteEndpoint); + const adSkipEndpointLogs = createRequestLogger(adSkipEndpoint); + const adStartEndpointLogs = createRequestLogger(adStartEndpoint); + const bitrateChangeEndpointLogs = createRequestLogger(bitrateChangeEndpoint); + const bufferStartEndpointLogs = createRequestLogger(bufferStartEndpoint); + const chapterCompleteEndpointLogs = createRequestLogger( + chapterCompleteEndpoint, + ); + const chapterSkipEndpointLogs = createRequestLogger(chapterSkipEndpoint); + const chapterStartEndpointLogs = createRequestLogger(chapterStartEndpoint); + const errorEndpointLogs = createRequestLogger(errorEndpoint); + const sessionCompleteEndpointLogs = createRequestLogger( + sessionCompleteEndpoint, + ); + const sessionEndEndpointLogs = createRequestLogger(sessionEndEndpoint); + const statesUpdateEndpointLogs = createRequestLogger(statesUpdateEndpoint); + + const clearLogs = async () => { + await edgeEndpointLogs.clear(); + await edgeCollectEndpointLogs.clear(); + await edgeInteractEndpointLogs.clear(); + await setConsentEndpointLogs.clear(); + await acquireEndpointLogs.clear(); + await targetDeliveryEndpointLogs.clear(); + await targetMboxJsonEndpointLogs.clear(); + await mediaPlayEndpointLogs.clear(); + await mediaPauseEndpointLogs.clear(); + await pingEndpointLogs.clear(); + await adBreakCompleteEndpointLogs.clear(); + await adBreakStartEndpointLogs.clear(); + await adCompleteEndpointLogs.clear(); + await adSkipEndpointLogs.clear(); + await adStartEndpointLogs.clear(); + await bitrateChangeEndpointLogs.clear(); + await bufferStartEndpointLogs.clear(); + await chapterCompleteEndpointLogs.clear(); + await chapterSkipEndpointLogs.clear(); + await chapterStartEndpointLogs.clear(); + await errorEndpointLogs.clear(); + await sessionCompleteEndpointLogs.clear(); + await sessionEndEndpointLogs.clear(); + await statesUpdateEndpointLogs.clear(); + }; + + return { + edgeEndpointLogs, + // Before using edgeCollectEndpointLogs in a test, check to see if you + // should be using the createCollectEndpointAssertion.js module instead. + edgeCollectEndpointLogs, + edgeInteractEndpointLogs, + setConsentEndpointLogs, + acquireEndpointLogs, + targetDeliveryEndpointLogs, + targetMboxJsonEndpointLogs, + mediaPlayEndpointLogs, + mediaPauseEndpointLogs, + pingEndpointLogs, + adBreakCompleteEndpointLogs, + adBreakStartEndpointLogs, + adCompleteEndpointLogs, + adSkipEndpointLogs, + adStartEndpointLogs, + bitrateChangeEndpointLogs, + bufferStartEndpointLogs, + chapterCompleteEndpointLogs, + chapterSkipEndpointLogs, + chapterStartEndpointLogs, + errorEndpointLogs, + sessionCompleteEndpointLogs, + sessionEndEndpointLogs, + statesUpdateEndpointLogs, + clearLogs, + }; +}; + +export default createNetworkLogger; diff --git a/packages/browser/test/functional/helpers/optIn/createMockOptIn.js b/packages/browser/test/functional/helpers/optIn/createMockOptIn.js new file mode 100644 index 000000000..912412cc3 --- /dev/null +++ b/packages/browser/test/functional/helpers/optIn/createMockOptIn.js @@ -0,0 +1,31 @@ +/* +Copyright 2020 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 { ClientFunction } from "testcafe"; + +export default ClientFunction((approved) => { + window.adobe = { + optIn: { + fetchPermissions(callback) { + setTimeout(() => { + callback(); + }, 0); + }, + isApproved() { + return approved; + }, + Categories: { + ECID: "ecid", + }, + }, + }; +}); diff --git a/packages/browser/test/functional/helpers/preventLinkNavigation.js b/packages/browser/test/functional/helpers/preventLinkNavigation.js new file mode 100644 index 000000000..df4bff1cc --- /dev/null +++ b/packages/browser/test/functional/helpers/preventLinkNavigation.js @@ -0,0 +1,24 @@ +/* +Copyright 2021 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 { ClientFunction } from "testcafe"; + +/** + * Prevents links from navigating the user. This can be particularly + * useful in tests that are asserting requests that would typically + * occur as a user navigates away from the page. + */ +export default ClientFunction(() => { + document.addEventListener("click", (event) => { + event.preventDefault(); + }); +}); diff --git a/packages/browser/test/functional/helpers/reloadPage.js b/packages/browser/test/functional/helpers/reloadPage.js new file mode 100644 index 000000000..e62ef7b82 --- /dev/null +++ b/packages/browser/test/functional/helpers/reloadPage.js @@ -0,0 +1,56 @@ +/* +Copyright 2020 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 { RELOAD_PAGE as RELOAD_PAGE_URL } from "./constants/url.js"; + +const getLocalStorageEntries = ClientFunction(() => { + const entries = Object.keys(window.localStorage) + // It seems that TestCafe modifies localStorage in such a way that + // Object.keys() returns not just the entry names, but also some methods, + // so we have to filter down to only those keys that are actual + // storage entries. + .filter((key) => localStorage.getItem(key) !== null) + .reduce((memo, entryName) => { + memo[entryName] = localStorage[entryName]; + return memo; + }, {}); + return entries; +}); + +const setLocalStorageEntries = ClientFunction((entries) => { + Object.keys(entries).forEach((entryName) => { + localStorage.setItem(entryName, entries[entryName]); + }); +}); + +const getCurrentUrl = ClientFunction(() => document.location.href); + +export default async (newQueryString = "") => { + const currentUrl = new URL(await getCurrentUrl()); + currentUrl.search = newQueryString; + // navigateTo waits for the server to respond after a redirect occurs, + // which is why we use it instead of just calling document.location.reload() + // in our client function. + // TestCafe + Safari have an issue where local storage is cleared when using + // t.navigateTo(), which is why we have to retrieve local storage entries + // and then restore them after navigation. + // https://github.com/DevExpress/testcafe/issues/5992 + // Also, we have to navigate to a different page and then back to the current page, + // because if we just tried to navigate to the same page we're on, TestCafe + // would hang in Safari (at least). + const localStorageEntries = await getLocalStorageEntries(); + // We could navigate to any other page and then back again. + await t.navigateTo(RELOAD_PAGE_URL); + await t.navigateTo(currentUrl.toString()); + await setLocalStorageEntries(localStorageEntries); +}; diff --git a/packages/browser/test/functional/helpers/requestHooks/demdexBlockerMock.js b/packages/browser/test/functional/helpers/requestHooks/demdexBlockerMock.js new file mode 100644 index 000000000..d45657a5a --- /dev/null +++ b/packages/browser/test/functional/helpers/requestHooks/demdexBlockerMock.js @@ -0,0 +1,23 @@ +/* +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 { RequestMock } from "testcafe"; + +// Mock that fails demdex requests +export default RequestMock() + .onRequestTo((request) => request.url.includes("demdex.net")) + .respond((req, res) => { + res.statusCode = 500; + res.headers = { + "content-type": "application/json", + }; + return ""; + }); diff --git a/packages/browser/test/functional/helpers/requestHooks/failOnceHook.js b/packages/browser/test/functional/helpers/requestHooks/failOnceHook.js new file mode 100644 index 000000000..c9e33db96 --- /dev/null +++ b/packages/browser/test/functional/helpers/requestHooks/failOnceHook.js @@ -0,0 +1,41 @@ +/* +Copyright 2020 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 { RequestHook } from "testcafe"; + +/** + * Useful for determining if requests were sent sequentially + * (a response from a request is received before the next request + * is sent). + */ +export default class FailOnceHook extends RequestHook { + constructor(...args) { + super(...args); + this.numRequests = 0; + } + + async onRequest() { + this.numRequests += 1; + } + + async onResponse() { + this.outstandingRequest = false; + } + + haveRequestsBeenSequential() { + return this.allRequestsSequential; + } + + getNumRequests() { + return this.numRequests; + } +} diff --git a/packages/browser/test/functional/helpers/requestHooks/sequentialHook.js b/packages/browser/test/functional/helpers/requestHooks/sequentialHook.js new file mode 100644 index 000000000..cab7225e9 --- /dev/null +++ b/packages/browser/test/functional/helpers/requestHooks/sequentialHook.js @@ -0,0 +1,47 @@ +/* +Copyright 2020 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 { RequestHook } from "testcafe"; + +/** + * Useful for determining if requests were sent sequentially + * (a response from a request is received before the next request + * is sent). + */ +export default class SequentialHook extends RequestHook { + constructor(...args) { + super(...args); + this.numRequests = 0; + this.outstandingRequest = false; + this.allRequestsSequential = true; + } + + async onRequest() { + this.numRequests += 1; + if (this.outstandingRequest) { + this.allRequestsSequential = false; + } + this.outstandingRequest = true; + } + + async onResponse() { + this.outstandingRequest = false; + } + + haveRequestsBeenSequential() { + return this.allRequestsSequential; + } + + getNumRequests() { + return this.numRequests; + } +} diff --git a/packages/browser/test/functional/helpers/sendBeaconMock.js b/packages/browser/test/functional/helpers/sendBeaconMock.js new file mode 100644 index 000000000..47202be4a --- /dev/null +++ b/packages/browser/test/functional/helpers/sendBeaconMock.js @@ -0,0 +1,48 @@ +/* +Copyright 2020 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 { ClientFunction } from "testcafe"; + +const mock = ClientFunction(() => { + const nativeSendBeacon = window.navigator.sendBeacon.bind(window.navigator); + window.navigator.sendBeacon = (...args) => { + const sendBeaconCallCount = Number( + sessionStorage.getItem("sendBeaconCallCount") || 0, + ); + sessionStorage.setItem("sendBeaconCallCount", sendBeaconCallCount + 1); + return nativeSendBeacon(...args); + }; +}); + +const getCallCount = ClientFunction(() => { + return Number(sessionStorage.getItem("sendBeaconCallCount") || 0); +}); + +const reset = ClientFunction(() => { + sessionStorage.removeItem("sendBeaconCallCount"); +}); + +/** + * Mocks and calls through to the native sendBeacon API. Useful for + * determining whether sendBeacon was used to make a network request. + * This is typically better than using a network logger because sendBeacon, + * at least in some browsers, asynchronously sends the request some time + * after sendBeacon is called. This would make it tricky to assert, for example, + * that a network request *wasn't* sent using sendBeacon because we would + * have to wait an arbitrary time period before checking the network logger + * to see that no requests were made to the collect endpoint. + */ +export default { + mock, + getCallCount, + reset, +}; diff --git a/packages/browser/test/functional/helpers/setLegacyIdentityCookie.js b/packages/browser/test/functional/helpers/setLegacyIdentityCookie.js new file mode 100644 index 000000000..8ef4d39f2 --- /dev/null +++ b/packages/browser/test/functional/helpers/setLegacyIdentityCookie.js @@ -0,0 +1,24 @@ +/* +Copyright 2020 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 } from "testcafe"; + +export default async (orgId) => { + const encodedOrgId = encodeURIComponent(orgId); + await t.setCookies({ + name: `AMCV_${encodedOrgId}`, + value: + "77933605%7CMCIDTS%7C18290%7CMCMID%7C16908443662402872073525706953453086963%7CMCAAMLH-1580857889%7C9%7CMCAAMB-1580857889%7CRKhpRz8krg2tLO6pguXWp5olkAcUniQYPHaMWWgdJ3xzPWQmdj0y%7CMCOPTOUT-1580260289s%7CNONE%7CvVersion%7C4.5.1", + domain: "alloyio.com", + path: "/", + }); +}; diff --git a/packages/browser/test/functional/helpers/visitorService/getVisitorEcid.js b/packages/browser/test/functional/helpers/visitorService/getVisitorEcid.js new file mode 100644 index 000000000..85200e5b5 --- /dev/null +++ b/packages/browser/test/functional/helpers/visitorService/getVisitorEcid.js @@ -0,0 +1,22 @@ +/* +Copyright 2020 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 { ClientFunction } from "testcafe"; + +export default ClientFunction((orgId) => { + return new Promise((resolve) => { + const visitor = window.Visitor.getInstance(orgId, {}); + visitor.getMarketingCloudVisitorID((ecid) => { + resolve(ecid); + }, true); + }); +}); diff --git a/packages/browser/test/functional/specs/Audiences/C12411.js b/packages/browser/test/functional/specs/Audiences/C12411.js new file mode 100644 index 000000000..79d660293 --- /dev/null +++ b/packages/browser/test/functional/specs/Audiences/C12411.js @@ -0,0 +1,56 @@ +/* +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 { RequestLogger, t } from "testcafe"; +import createNetworkLogger from "../../helpers/networkLogger/index.js"; +import createFixture from "../../helpers/createFixture/index.js"; +import { orgMainConfigMain } from "../../helpers/constants/configParts/index.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; + +const networkLogger = createNetworkLogger(); + +const networkLoggerConfig = { + logRequestBody: true, + stringifyRequestBody: true, +}; + +const destinationLogger = RequestLogger( + "https://cataas.com/cat", + networkLoggerConfig, +); + +createFixture({ + title: + "C12411 Response should return URL destinations if turned on in Blackbird", + requestHooks: [networkLogger.edgeEndpointLogs, destinationLogger], +}); + +test.meta({ + ID: "C12411", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +// This test is skipped because there's a bug in TestCafe where the request logger doesn't +// log the request of the URL destination image if the image is loaded inside an iframe. +// The image is loaded inside an iframe because hideReferrer is set to true for the +// URL destination. We could fix this test by setting hideReferrer to false so that +// the image is loaded outside an iframe, but there seems to be another bug at or +// behind Konductor preventing us from doing so. +// https://github.com/DevExpress/testcafe/issues/6060 +// https://jira.corp.adobe.com/browse/PDCL-4709 +test.skip("C12411 Response should return URL destinations if turned on in Blackbird", async () => { + const alloy = createAlloyProxy(); + await alloy.configure(orgMainConfigMain); + await alloy.sendEvent(); + + await t.expect(destinationLogger.requests.length > 0).eql(true); +}); diff --git a/packages/browser/test/functional/specs/Audiences/C12412.js b/packages/browser/test/functional/specs/Audiences/C12412.js new file mode 100644 index 000000000..7895402c7 --- /dev/null +++ b/packages/browser/test/functional/specs/Audiences/C12412.js @@ -0,0 +1,74 @@ +/* +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 createNetworkLogger from "../../helpers/networkLogger/index.js"; +import createFixture from "../../helpers/createFixture/index.js"; +import { + compose, + orgMainConfigMain, + debugEnabled, +} from "../../helpers/constants/configParts/index.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; +import createConsoleLogger from "../../helpers/consoleLogger/index.js"; + +const networkLogger = createNetworkLogger(); + +createFixture( + `C12412 Response should return Cookie destinations if turned on in Blackbird`, + { + requestHooks: [networkLogger.edgeEndpointLogs], + meta: { + ID: "C12412", + SEVERITY: "P0", + TEST_RUN: "Regression", + }, + }, +); + +const getDocumentCookie = ClientFunction(() => document.cookie); + +test(`Verify cookie destinations are returned in the response when turned on in Blackbird`, async () => { + const logger = await createConsoleLogger(); + const alloy = createAlloyProxy(); + + await alloy.configure(compose(orgMainConfigMain, debugEnabled)); + await alloy.sendEvent(); + + await t.expect(getDocumentCookie()).contains("C12412=test%3DC12412"); + + const logs = await logger.info.getMessagesSinceReset(); + const setCookieAttributes = logs + .filter( + (message) => message.length === 3 && message[1] === `Setting cookie`, + ) + .map((message) => message[2]) + .filter((cookieSettings) => cookieSettings.name === "C12412"); + + await t.expect(setCookieAttributes.length).eql(1); + await t.expect(setCookieAttributes[0].sameSite).eql("none"); + await t.expect(setCookieAttributes[0].secure).eql(true); +}); + +test(`Verify cookie is set on the / path `, async () => { + const alloy = createAlloyProxy(); + + await alloy.configure(compose(orgMainConfigMain, debugEnabled)); + await alloy.sendEvent(); + + const cookies = await t.getCookies("C12412"); + + // In Firefox, the t.getCookies method returns an empty array even if the cookie is present. + // The if condition below is to handle this issue. + if (cookies.length > 0) { + await t.expect(cookies[0].path).eql("/"); + } +}); diff --git a/packages/browser/test/functional/specs/Audiences/C31436.js b/packages/browser/test/functional/specs/Audiences/C31436.js new file mode 100644 index 000000000..faa72529b --- /dev/null +++ b/packages/browser/test/functional/specs/Audiences/C31436.js @@ -0,0 +1,57 @@ +/* +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 { RequestLogger, t } from "testcafe"; +import createNetworkLogger from "../../helpers/networkLogger/index.js"; +import createFixture from "../../helpers/createFixture/index.js"; +import { orgMainConfigMain } from "../../helpers/constants/configParts/index.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; + +const networkLogger = createNetworkLogger(); + +const networkLoggerConfig = { + logRequestBody: true, + stringifyRequestBody: true, +}; + +const destinationLogger = RequestLogger( + "https://cataas.com/cat/cute", + networkLoggerConfig, +); + +createFixture({ + title: "C31436 Qualify for URL destinations via XDM Data.", + requestHooks: [networkLogger.edgeEndpointLogs, destinationLogger], +}); + +test.meta({ + ID: "C31436", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +// This test is skipped because there's a bug in TestCafe where the request logger doesn't +// log the request of the URL destination image if the image is loaded inside an iframe. +// The image is loaded inside an iframe because hideReferrer is set to true for the +// URL destination. We could fix this test by setting hideReferrer to false so that +// the image is loaded outside an iframe, but there seems to be another bug at or +// behind Konductor preventing us from doing so. +// https://github.com/DevExpress/testcafe/issues/6060 +// https://jira.corp.adobe.com/browse/PDCL-4709 +test.skip("C31436 Qualify for URL destinations via XDM Data.", async () => { + const alloy = createAlloyProxy(); + await alloy.configure(orgMainConfigMain); + await alloy.sendEvent({ + xdm: { web: { webPageDetails: { name: "C31436" } } }, + }); + + await t.expect(destinationLogger.requests.length).eql(1); +}); diff --git a/packages/browser/test/functional/specs/CNAME/C148846.js b/packages/browser/test/functional/specs/CNAME/C148846.js new file mode 100644 index 000000000..b6e97b96a --- /dev/null +++ b/packages/browser/test/functional/specs/CNAME/C148846.js @@ -0,0 +1,101 @@ +/* +Copyright 2020 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 } from "testcafe"; +import createNetworkLogger from "../../helpers/networkLogger/index.js"; +import createFixture from "../../helpers/createFixture/index.js"; +import { + compose, + edgeDomainFirstParty, + orgMainConfigMain, +} from "../../helpers/constants/configParts/index.js"; +import { FIRST_PARTY_DOMAIN } from "../../helpers/constants/domain.js"; +import getResponseBody from "../../helpers/networkLogger/getResponseBody.js"; +import createResponse from "../../helpers/createResponse.js"; +import areThirdPartyCookiesSupported from "../../helpers/areThirdPartyCookiesSupported.js"; +import { MAIN_IDENTITY_COOKIE_NAME } from "../../helpers/constants/cookies.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; + +const demdexUrlRegex = /\.demdex\.net/; + +const getUrlFor = (requestLogger) => requestLogger.request.url; + +const config = compose(orgMainConfigMain, edgeDomainFirstParty); + +test.meta({ + ID: "C148846", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +const networkLogger = createNetworkLogger(); +createFixture({ + title: "C148846 - Setting edgeDomain to CNAME", + requestHooks: [networkLogger.edgeInteractEndpointLogs], +}); + +test("C148846 - Setting edgeDomain to CNAME results in server calls to this CNAME", async () => { + const alloy = createAlloyProxy(); + await alloy.configure(config); + await alloy.sendEvent(); + await alloy.sendEvent(); + + const firstRequest = networkLogger.edgeInteractEndpointLogs.requests[0]; + // const secondRequest = networkLogger.edgeInteractEndpointLogs.requests[1]; + + const responseForDemdexRequest = JSON.parse(getResponseBody(firstRequest)); + // const responseForCnameRequest = JSON.parse(getResponseBody(secondRequest)); + + const alloyDemdexResponse = createResponse({ + content: responseForDemdexRequest, + }); + const demdexStateHandle = + alloyDemdexResponse.getPayloadsByType("state:store"); + + // const alloyCnameResponse = createResponse({ content: responseForCnameRequest }); + // const cnameStateHandle = alloyCnameResponse.getPayloadsByType("state:store"); + + const demdexResponseContainsIdentityCookie = demdexStateHandle.find((h) => + h.key.includes(MAIN_IDENTITY_COOKIE_NAME), + ); + + const urlForFirstRequest = getUrlFor(firstRequest); + // const hostForSecondRequest = getHostFor(secondRequest); + + if (areThirdPartyCookiesSupported()) { + await t.expect(urlForFirstRequest).match(demdexUrlRegex); + // await t.expect(hostForSecondRequest).contains(FIRST_PARTY_DOMAIN); + + // Expects the demdex response to contain Konductor state. + // Expects the demdex state to contain the identity cookie. + await t.expect(demdexStateHandle.length).gte(0); + await t.expect(demdexResponseContainsIdentityCookie).ok(); + } else { + await t.expect(urlForFirstRequest).contains(FIRST_PARTY_DOMAIN); + // await t.expect(hostForSecondRequest).contains(FIRST_PARTY_DOMAIN); + } + + // We don't believe these assertions are valid. When running this test locally on Firefox, + // Testcafe adds an additional identifier to the cookie. + + // Expects the CNAME request header to contain the Konductor state cookies. + // Expects the CNAME response body to not contain the Konductor state. + // Expects the CNAME response header to contain the Konductor state. + // await t + // .expect(secondRequest.request.headers.cookie) + // .contains(MAIN_IDENTITY_COOKIE_NAME); + // await t.expect(cnameStateHandle.length).eql(0); + // await t.expect(secondRequest.response.headers["set-cookie"]).ok(); + // await t + // .expect(secondRequest.response.headers["set-cookie"][0]) + // .contains(MAIN_IDENTITY_COOKIE_NAME); +}); diff --git a/packages/browser/test/functional/specs/Command Logic/C11634155.js b/packages/browser/test/functional/specs/Command Logic/C11634155.js new file mode 100644 index 000000000..e936a4c02 --- /dev/null +++ b/packages/browser/test/functional/specs/Command Logic/C11634155.js @@ -0,0 +1,73 @@ +/* +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 { + compose, + debugEnabled, + orgMainConfigMain, +} from "../../helpers/constants/configParts/index.js"; +import createFixture from "../../helpers/createFixture/index.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; +import createNetworkLogger from "../../helpers/networkLogger/index.js"; +import { responseStatus } from "../../helpers/assertions/index.js"; +import createConsoleLogger from "../../helpers/consoleLogger/index.js"; + +const networkLogger = createNetworkLogger(); +const config = compose(orgMainConfigMain, debugEnabled, { + edgeConfigId: orgMainConfigMain.datastreamId, +}); +delete config.datastreamId; + +createFixture({ + title: "C11634155: Deprecates options like edgeConfigId and warns with use", + requestHooks: [networkLogger.edgeEndpointLogs], +}); + +test.meta({ + ID: "C11634155", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +test("Test C11634155: Deprecates options like edgeConfigId and warns with use", async () => { + const logger = await createConsoleLogger(); + + const alloy = createAlloyProxy(); + await alloy.configure(config); + + await logger.warn.expectMessageMatching( + /The field 'edgeConfigId' is deprecated./, + ); +}); + +test("Test C11634155: Deprecates options like edgeConfigId and warns when both are used", async () => { + const logger = await createConsoleLogger(); + const configWithBoth = { ...config, datastreamId: config.edgeConfigId }; + + const alloy = createAlloyProxy(); + await alloy.configure(configWithBoth); + + await logger.warn.expectMessageMatching( + /The field 'edgeConfigId' is deprecated./, + ); +}); + +test("Test C11634155: When specifying a deprecated option like edgeConfigId, it uses the specified alternative, datastreamId", async (t) => { + const alloy = createAlloyProxy(); + await alloy.configureAsync(config); + + await alloy.sendEvent({}); + + await responseStatus(networkLogger.edgeEndpointLogs.requests, [200, 207]); + await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(1); + const { url } = networkLogger.edgeEndpointLogs.requests[0].request; + await t.expect(url).contains(config.edgeConfigId); +}); diff --git a/packages/browser/test/functional/specs/Command Logic/C13816.js b/packages/browser/test/functional/specs/Command Logic/C13816.js new file mode 100644 index 000000000..98166a393 --- /dev/null +++ b/packages/browser/test/functional/specs/Command Logic/C13816.js @@ -0,0 +1,35 @@ +/* +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 createAlloyProxy from "../../helpers/createAlloyProxy.js"; +import createFixture from "../../helpers/createFixture/index.js"; + +createFixture({ + title: "C13816: Throws error when configure has no options", +}); + +test.meta({ + ID: "C13816", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +test("Test C13816: Throws error when configure has no options", async (t) => { + const alloy = createAlloyProxy(); + const configureErrorMessage = await alloy.configureErrorMessage(); + + await t + .expect(configureErrorMessage) + .ok("Configure didn't throw an exception."); + await t.expect(configureErrorMessage).contains("orgId"); + await t.expect(configureErrorMessage).contains("datastreamId"); + await t.expect(configureErrorMessage).contains("documentation"); +}); diff --git a/packages/browser/test/functional/specs/Command Logic/C13817.js b/packages/browser/test/functional/specs/Command Logic/C13817.js new file mode 100644 index 000000000..9560e52a7 --- /dev/null +++ b/packages/browser/test/functional/specs/Command Logic/C13817.js @@ -0,0 +1,30 @@ +/* +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 createAlloyProxy from "../../helpers/createAlloyProxy.js"; +import createFixture from "../../helpers/createFixture/index.js"; + +createFixture({ + title: "C13817: Throws error when running command after bad configure", +}); + +test.meta({ + ID: "C13817", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +test("Test C13817: Throws error when running command after bad configure", async (t) => { + const alloy = createAlloyProxy(); + await alloy.configureErrorMessage(); + const eventErrorMessage = await alloy.sendEventErrorMessage(); + await t.expect(eventErrorMessage).contains("configured"); +}); diff --git a/packages/browser/test/functional/specs/Command Logic/C13818.js b/packages/browser/test/functional/specs/Command Logic/C13818.js new file mode 100644 index 000000000..e446da230 --- /dev/null +++ b/packages/browser/test/functional/specs/Command Logic/C13818.js @@ -0,0 +1,63 @@ +/* +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 { RequestLogger, ClientFunction } from "testcafe"; +import createFixture from "../../helpers/createFixture/index.js"; + +import { + orgMainConfigMain, + orgAltConfigAlt, +} from "../../helpers/constants/configParts/index.js"; + +const networkLoggerConfig = { + logRequestBody: true, + stringifyRequestBody: true, +}; +const networkLogger1 = RequestLogger( + new RegExp( + `v1\\/(interact|collect)\\?configId=${orgMainConfigMain.datastreamId}`, + ), + networkLoggerConfig, +); +const networkLogger2 = RequestLogger( + new RegExp( + `v1\\/(interact|collect)\\?configId=${orgAltConfigAlt.datastreamId}`, + ), + networkLoggerConfig, +); + +createFixture({ + title: + "C13818: Changing the options object after configure doesn't change the computed config", + requestHooks: [networkLogger1, networkLogger2], +}); + +test.meta({ + ID: "C13818", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +const apiCalls = ClientFunction((configObject, alternateConfigObject) => { + return window.alloy("configure", configObject).then(() => { + Object.keys(alternateConfigObject).forEach((key) => { + configObject[key] = alternateConfigObject[key]; + }); + return window.alloy("sendEvent"); + }); +}); + +test("Test C13818: Changing the options object after configure doesn't change the computed config", async (t) => { + await apiCalls(orgMainConfigMain, orgAltConfigAlt); + + await t.expect(networkLogger1.requests.length).eql(1); + await t.expect(networkLogger2.requests.length).eql(0); +}); diff --git a/packages/browser/test/functional/specs/Command Logic/C13819.js b/packages/browser/test/functional/specs/Command Logic/C13819.js new file mode 100644 index 000000000..56a12c396 --- /dev/null +++ b/packages/browser/test/functional/specs/Command Logic/C13819.js @@ -0,0 +1,47 @@ +/* +Copyright 2021 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 { ClientFunction } from "testcafe"; +import { + compose, + orgMainConfigMain, +} from "../../helpers/constants/configParts/index.js"; +import createFixture from "../../helpers/createFixture/index.js"; +import configureAlloyInstance from "../../helpers/configureAlloyInstance/index.js"; + +const config = compose(orgMainConfigMain, { + datastreamId: "BOGUS", +}); + +createFixture({ + title: + "C13819: Sending invalid config ID rejects command promise with useful error", +}); + +test.meta({ + ID: "C13819", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +const sendEvent = ClientFunction(() => { + return window.alloy("sendEvent").catch((e) => e.message); +}); + +test("Test C13819: Sending invalid config ID rejects command promise with useful error", async (t) => { + await configureAlloyInstance("alloy", config); + const errorMessage = await sendEvent(); + await t + .expect(errorMessage) + .contains("The server responded with a status code 400 and response body"); + await t.expect(errorMessage).contains("EXEG-0003-400"); +}); diff --git a/packages/browser/test/functional/specs/Command Logic/C2580.js b/packages/browser/test/functional/specs/Command Logic/C2580.js new file mode 100644 index 000000000..37923ffbe --- /dev/null +++ b/packages/browser/test/functional/specs/Command Logic/C2580.js @@ -0,0 +1,48 @@ +/* +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 { injectAlloyDuringTest } from "../../helpers/createFixture/clientScripts.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; + +const debugEnabledConfig = compose(orgMainConfigMain, debugEnabled); + +createFixture({ + title: "C2580: Command queueing test", + includeAlloyLibrary: false, +}); + +test.meta({ + ID: "C2580", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +const getAlloyCommandQueueLength = ClientFunction(() => { + return window.alloy.q.length; +}); + +test("C2580: Command queueing test.", async () => { + const alloy = createAlloyProxy(); + await alloy.configureAsync(debugEnabledConfig); + await alloy.getLibraryInfoAsync(); + await t.expect(getAlloyCommandQueueLength()).eql(2); + const logger = await createConsoleLogger(); + await injectAlloyDuringTest(); + await logger.info.expectMessageMatching(/Executing getLibraryInfo command/); +}); diff --git a/packages/browser/test/functional/specs/Command Logic/C2585.js b/packages/browser/test/functional/specs/Command Logic/C2585.js new file mode 100644 index 000000000..8ac8f61cd --- /dev/null +++ b/packages/browser/test/functional/specs/Command Logic/C2585.js @@ -0,0 +1,35 @@ +/* +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 createAlloyProxy from "../../helpers/createAlloyProxy.js"; +import createFixture from "../../helpers/createFixture/index.js"; + +createFixture({ + title: + "C2585: Throws error when configure is not the first command executed.", +}); + +test.meta({ + ID: "C2585", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +test("Test C2585: Throw error when configure is not the first command executed.", async (t) => { + // Note: unable to enable logging with url parameter or enabler logger config. + const alloy = createAlloyProxy(); + const sendEventErrorMessage = await alloy.sendEventErrorMessage(); + await t + .expect(sendEventErrorMessage) + .match( + /The library must be configured first. Please do so by executing the configure command./, + ); +}); diff --git a/packages/browser/test/functional/specs/Command Logic/C2587.js b/packages/browser/test/functional/specs/Command Logic/C2587.js new file mode 100644 index 000000000..c36daa7d6 --- /dev/null +++ b/packages/browser/test/functional/specs/Command Logic/C2587.js @@ -0,0 +1,48 @@ +/* +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 { ClientFunction } from "testcafe"; +import createFixture from "../../helpers/createFixture/index.js"; +import { + compose, + orgMainConfigMain, + debugEnabled, +} from "../../helpers/constants/configParts/index.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; + +const config = compose(orgMainConfigMain, debugEnabled); + +createFixture({ + title: "C2587: Throw error when executing command that doesn't exist.", +}); + +test.meta({ + ID: "C2587", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +const bogusCommand = ClientFunction(() => { + return window.alloy("bogusCommand").then( + () => {}, + (error) => error.message, + ); +}); + +test("Test C2587: Throw error when executing command that doesn't exist", async (t) => { + const alloy = createAlloyProxy(); + await alloy.configure(config); + + const errorMessage = await bogusCommand(); + await t + .expect(errorMessage) + .match(/The bogusCommand command does not exist./); +}); diff --git a/packages/browser/test/functional/specs/Command Logic/C2588.js b/packages/browser/test/functional/specs/Command Logic/C2588.js new file mode 100644 index 000000000..b812ed4eb --- /dev/null +++ b/packages/browser/test/functional/specs/Command Logic/C2588.js @@ -0,0 +1,36 @@ +/* +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 createFixture from "../../helpers/createFixture/index.js"; +import { orgMainConfigMain } from "../../helpers/constants/configParts/index.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; + +createFixture({ + title: "C2588: Throws error when configure is executed multiple times.", +}); + +test.meta({ + ID: "C2588", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +test("Test C2588: Throw error when configure is executed multiple times.", async (t) => { + const alloy = createAlloyProxy(); + await alloy.configure(orgMainConfigMain); + const errorMessage = await alloy.configureErrorMessage(orgMainConfigMain); + + await t + .expect(errorMessage) + .match( + /The library has already been configured and may only be configured once./, + ); +}); diff --git a/packages/browser/test/functional/specs/Command Logic/C3484892.js b/packages/browser/test/functional/specs/Command Logic/C3484892.js new file mode 100644 index 000000000..46c60f9dc --- /dev/null +++ b/packages/browser/test/functional/specs/Command Logic/C3484892.js @@ -0,0 +1,33 @@ +/* +Copyright 2021 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 createFixture from "../../helpers/createFixture/index.js"; +import { orgMainConfigMain } from "../../helpers/constants/configParts/index.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; + +const title = + "C3484892: Resolves promise with empty result object from configure command."; + +createFixture({ + title, +}); + +test.meta({ + ID: "C3484892", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +test(title, async (t) => { + const alloy = createAlloyProxy(); + const result = await alloy.configure(orgMainConfigMain); + await t.expect(result).eql({}); +}); diff --git a/packages/browser/test/functional/specs/Config Overrides/C7437530.js b/packages/browser/test/functional/specs/Config Overrides/C7437530.js new file mode 100644 index 000000000..ae89bae74 --- /dev/null +++ b/packages/browser/test/functional/specs/Config Overrides/C7437530.js @@ -0,0 +1,239 @@ +/* +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 } from "testcafe"; +import createNetworkLogger from "../../helpers/networkLogger/index.js"; +import { responseStatus } from "../../helpers/assertions/index.js"; +import createFixture from "../../helpers/createFixture/index.js"; +import { + compose, + configOverridesMain as overrides, + configOverridesAlt as alternateOverrides, + orgMainConfigMain, + debugEnabled, +} from "../../helpers/constants/configParts/index.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; + +const networkLogger = createNetworkLogger(); +const config = compose(orgMainConfigMain, debugEnabled); + +createFixture({ + title: + "C7437530: sendEvent can receive config overrides in command options and in configure", + requestHooks: [networkLogger.edgeEndpointLogs], +}); + +test.meta({ + ID: "C2592", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +test("Test C7437530: `sendEvent` can receive config overrides in command options", async () => { + const alloy = createAlloyProxy(); + await alloy.configure(config); + await alloy.sendEvent({ + edgeConfigOverrides: overrides, + }); + + await responseStatus(networkLogger.edgeEndpointLogs.requests, [200, 207]); + + await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(1); + + const request = JSON.parse( + networkLogger.edgeEndpointLogs.requests[0].request.body, + ); + + await t + .expect(request.events[0].xdm.implementationDetails.name) + .eql("https://ns.adobe.com/experience/alloy"); + await t + .expect( + request.meta.configOverrides.com_adobe_experience_platform.datasets.event, + ) + .eql(overrides.com_adobe_experience_platform.datasets.event); + await t + .expect(request.meta.configOverrides.com_adobe_analytics.reportSuites) + .eql(overrides.com_adobe_analytics.reportSuites); + await t + .expect(request.meta.configOverrides.com_adobe_identity.idSyncContainerId) + .eql(overrides.com_adobe_identity.idSyncContainerId); + await t + .expect(request.meta.configOverrides.com_adobe_target.propertyToken) + .eql(overrides.com_adobe_target.propertyToken); + await t.expect(request.meta.state.cookiesEnabled).eql(true); + await t.expect(request.meta.state.domain).ok(); +}); + +test("Test C7437530: `sendEvent` doesn't contain empty configOverrides if edgeConfigOverrides are not in options", async () => { + const alloy = createAlloyProxy(); + await alloy.configure(config); + await alloy.sendEvent({}); + + await responseStatus(networkLogger.edgeEndpointLogs.requests, [200, 207]); + + await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(1); + + const request = JSON.parse( + networkLogger.edgeEndpointLogs.requests[0].request.body, + ); + + await t + .expect(request.events[0].xdm.implementationDetails.name) + .eql("https://ns.adobe.com/experience/alloy"); + await t.expect(request.meta.configOverrides).eql(undefined); +}); + +test("Test C7437530: `sendEvent` can receive config overrides from configure", async () => { + const alloy = createAlloyProxy(); + await alloy.configure( + compose(config, { + edgeConfigOverrides: overrides, + }), + ); + await alloy.sendEvent({}); + + await responseStatus(networkLogger.edgeEndpointLogs.requests, [200, 207]); + + await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(1); + + const request = JSON.parse( + networkLogger.edgeEndpointLogs.requests[0].request.body, + ); + + await t + .expect(request.events[0].xdm.implementationDetails.name) + .eql("https://ns.adobe.com/experience/alloy"); + await t + .expect( + request.meta.configOverrides.com_adobe_experience_platform.datasets.event, + ) + .eql(overrides.com_adobe_experience_platform.datasets.event); + await t + .expect(request.meta.configOverrides.com_adobe_analytics.reportSuites) + .eql(overrides.com_adobe_analytics.reportSuites); + await t + .expect(request.meta.configOverrides.com_adobe_identity.idSyncContainerId) + .eql(overrides.com_adobe_identity.idSyncContainerId); + await t + .expect(request.meta.configOverrides.com_adobe_target.propertyToken) + .eql(overrides.com_adobe_target.propertyToken); + await t.expect(request.meta.state.cookiesEnabled).eql(true); + await t.expect(request.meta.state.domain).ok(); +}); + +test("Test C7437530: overrides from `sendEvent` should take precedence over the ones from `configure`", async () => { + const alloy = createAlloyProxy(); + await alloy.configure( + compose(config, { + edgeConfigOverrides: alternateOverrides, + }), + ); + await alloy.sendEvent({ + edgeConfigOverrides: overrides, + }); + + await responseStatus(networkLogger.edgeEndpointLogs.requests, [200, 207]); + + await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(1); + + const request = JSON.parse( + networkLogger.edgeEndpointLogs.requests[0].request.body, + ); + + await t + .expect(request.events[0].xdm.implementationDetails.name) + .eql("https://ns.adobe.com/experience/alloy"); + await t + .expect( + request.meta.configOverrides.com_adobe_experience_platform.datasets.event, + ) + .eql(overrides.com_adobe_experience_platform.datasets.event); + await t + .expect(request.meta.configOverrides.com_adobe_analytics.reportSuites) + .eql(overrides.com_adobe_analytics.reportSuites); + await t + .expect(request.meta.configOverrides.com_adobe_identity.idSyncContainerId) + .eql(overrides.com_adobe_identity.idSyncContainerId); + await t + .expect(request.meta.configOverrides.com_adobe_target.propertyToken) + .eql(overrides.com_adobe_target.propertyToken); + await t.expect(request.meta.state.cookiesEnabled).eql(true); + await t.expect(request.meta.state.domain).ok(); +}); + +test("Test C7437530: empty configuration overrides should not be sent to the Edge", async () => { + const alloy = createAlloyProxy(); + await alloy.configure( + compose(config, { + edgeConfigOverrides: compose(alternateOverrides, { + com_adobe_target: { + propertyToken: "", + }, + }), + }), + ); + await alloy.sendEvent({ + edgeConfigOverrides: compose(overrides, { + com_adobe_target: { + propertyToken: "", + }, + }), + }); + + await responseStatus(networkLogger.edgeEndpointLogs.requests, [200, 207]); + + await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(1); + + const request = JSON.parse( + networkLogger.edgeEndpointLogs.requests[0].request.body, + ); + + await t + .expect(request.events[0].xdm.implementationDetails.name) + .eql("https://ns.adobe.com/experience/alloy"); + await t + .expect( + request.meta.configOverrides.com_adobe_experience_platform.datasets.event, + ) + .eql(overrides.com_adobe_experience_platform.datasets.event); + await t + .expect(request.meta.configOverrides.com_adobe_analytics.reportSuites) + .eql(overrides.com_adobe_analytics.reportSuites); + await t + .expect(request.meta.configOverrides.com_adobe_identity.idSyncContainerId) + .eql(overrides.com_adobe_identity.idSyncContainerId); + await t.expect(request.meta.configOverrides.com_adobe_target).eql(undefined); + await t.expect(request.meta.state.cookiesEnabled).eql(true); + await t.expect(request.meta.state.domain).ok(); +}); + +test("Test C7437530: `sendEvent` can override the datastreamId", async () => { + const alloy = createAlloyProxy(); + await alloy.configure(config); + const { datastreamId: originalDatastreamId } = config; + const alternateDatastreamId = `${originalDatastreamId}:dev`; + await alloy.sendEvent({ + edgeConfigOverrides: { + datastreamId: alternateDatastreamId, + }, + }); + + await responseStatus(networkLogger.edgeEndpointLogs.requests, [200, 207]); + await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(1); + const [request] = networkLogger.edgeEndpointLogs.requests; + await t.expect(request.request.url).contains(alternateDatastreamId); + + const body = JSON.parse(request.request.body); + await t + .expect(body.meta.sdkConfig.datastream.original) + .eql(originalDatastreamId); +}); diff --git a/packages/browser/test/functional/specs/Config Overrides/C7437531.js b/packages/browser/test/functional/specs/Config Overrides/C7437531.js new file mode 100644 index 000000000..e5136b16e --- /dev/null +++ b/packages/browser/test/functional/specs/Config Overrides/C7437531.js @@ -0,0 +1,184 @@ +/* +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 } from "testcafe"; +import createNetworkLogger from "../../helpers/networkLogger/index.js"; +import { responseStatus } from "../../helpers/assertions/index.js"; +import createFixture from "../../helpers/createFixture/index.js"; +import { + compose, + configOverridesMain as overrides, + configOverridesAlt as alternateOverrides, + orgMainConfigMain, + debugEnabled, +} from "../../helpers/constants/configParts/index.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; + +const networkLogger = createNetworkLogger(); +const config = compose(orgMainConfigMain, debugEnabled); + +createFixture({ + title: + "C7437531: `getIdentity` can receive config overrides in command options and in `configure`", + requestHooks: [networkLogger.acquireEndpointLogs], +}); + +test.meta({ + ID: "C2592", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +test("Test C7437531: `getIdentity` can receive config overrides in command options", async () => { + const alloy = createAlloyProxy(); + await alloy.configure(config); + // this should get an ECID + await alloy.getIdentity({ + edgeConfigOverrides: overrides, + }); + + await responseStatus(networkLogger.acquireEndpointLogs.requests, [200, 207]); + await t.expect(networkLogger.acquireEndpointLogs.requests.length).eql(1); + + const request = JSON.parse( + networkLogger.acquireEndpointLogs.requests[0].request.body, + ); + + await t + .expect( + request.meta.configOverrides.com_adobe_experience_platform.datasets.event, + ) + .eql(overrides.com_adobe_experience_platform.datasets.event); + await t + .expect(request.meta.configOverrides.com_adobe_analytics.reportSuites) + .eql(overrides.com_adobe_analytics.reportSuites); + await t + .expect(request.meta.configOverrides.com_adobe_identity.idSyncContainerId) + .eql(overrides.com_adobe_identity.idSyncContainerId); + await t + .expect(request.meta.configOverrides.com_adobe_target.propertyToken) + .eql(overrides.com_adobe_target.propertyToken); +}); + +test("Test C7437531: `getIdentity` can receive config overrides from `configure`", async () => { + const alloy = createAlloyProxy(); + await alloy.configure(compose(config, { edgeConfigOverrides: overrides })); + // this should get an ECID + await alloy.getIdentity(); + + await responseStatus(networkLogger.acquireEndpointLogs.requests, [200, 207]); + await t.expect(networkLogger.acquireEndpointLogs.requests.length).eql(1); + + const request = JSON.parse( + networkLogger.acquireEndpointLogs.requests[0].request.body, + ); + + await t + .expect( + request.meta.configOverrides.com_adobe_experience_platform.datasets.event, + ) + .eql(overrides.com_adobe_experience_platform.datasets.event); + await t + .expect(request.meta.configOverrides.com_adobe_analytics.reportSuites) + .eql(overrides.com_adobe_analytics.reportSuites); + await t + .expect(request.meta.configOverrides.com_adobe_identity.idSyncContainerId) + .eql(overrides.com_adobe_identity.idSyncContainerId); + await t + .expect(request.meta.configOverrides.com_adobe_target.propertyToken) + .eql(overrides.com_adobe_target.propertyToken); +}); + +test("Test C7437531: overrides from `getIdentity` should take precedence over the ones from `configure`", async () => { + const alloy = createAlloyProxy(); + await alloy.configure( + compose(config, { edgeConfigOverrides: alternateOverrides }), + ); + // this should get an ECID + await alloy.getIdentity({ edgeConfigOverrides: overrides }); + + await responseStatus(networkLogger.acquireEndpointLogs.requests, [200, 207]); + await t.expect(networkLogger.acquireEndpointLogs.requests.length).eql(1); + + const request = JSON.parse( + networkLogger.acquireEndpointLogs.requests[0].request.body, + ); + + await t + .expect( + request.meta.configOverrides.com_adobe_experience_platform.datasets.event, + ) + .eql(overrides.com_adobe_experience_platform.datasets.event); + await t + .expect(request.meta.configOverrides.com_adobe_analytics.reportSuites) + .eql(overrides.com_adobe_analytics.reportSuites); + await t + .expect(request.meta.configOverrides.com_adobe_identity.idSyncContainerId) + .eql(overrides.com_adobe_identity.idSyncContainerId); + await t + .expect(request.meta.configOverrides.com_adobe_target.propertyToken) + .eql(overrides.com_adobe_target.propertyToken); +}); + +test("Test C7437531: empty configuration overrides should not be sent to the Edge", async () => { + const alloy = createAlloyProxy(); + await alloy.configure(config); + // this should get an ECID + await alloy.getIdentity({ + edgeConfigOverrides: compose(overrides, { + com_adobe_target: { + propertyToken: "", + }, + }), + }); + + await responseStatus(networkLogger.acquireEndpointLogs.requests, [200, 207]); + await t.expect(networkLogger.acquireEndpointLogs.requests.length).eql(1); + + const request = JSON.parse( + networkLogger.acquireEndpointLogs.requests[0].request.body, + ); + + await t + .expect( + request.meta.configOverrides.com_adobe_experience_platform.datasets.event, + ) + .eql(overrides.com_adobe_experience_platform.datasets.event); + await t + .expect(request.meta.configOverrides.com_adobe_analytics.reportSuites) + .eql(overrides.com_adobe_analytics.reportSuites); + await t + .expect(request.meta.configOverrides.com_adobe_identity.idSyncContainerId) + .eql(overrides.com_adobe_identity.idSyncContainerId); + await t.expect(request.meta.configOverrides.com_adobe_target).eql(undefined); +}); + +test("Test C7437531: `getIdentity` can override the datastreamId", async () => { + const alloy = createAlloyProxy(); + await alloy.configure(config); + const { datastreamId: originalDatastreamId } = config; + const alternateDatastreamId = `${originalDatastreamId}:dev`; + await alloy.getIdentity({ + edgeConfigOverrides: { + datastreamId: alternateDatastreamId, + }, + }); + + await responseStatus(networkLogger.acquireEndpointLogs.requests, [200, 207]); + await t.expect(networkLogger.acquireEndpointLogs.requests.length).eql(1); + const [request] = networkLogger.acquireEndpointLogs.requests; + await t.expect(request.request.url).contains(alternateDatastreamId); + + const body = JSON.parse(request.request.body); + await t + .expect(body.meta.sdkConfig.datastream.original) + .eql(originalDatastreamId); +}); diff --git a/packages/browser/test/functional/specs/Config Overrides/C7437532.js b/packages/browser/test/functional/specs/Config Overrides/C7437532.js new file mode 100644 index 000000000..643975afc --- /dev/null +++ b/packages/browser/test/functional/specs/Config Overrides/C7437532.js @@ -0,0 +1,192 @@ +/* +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 } from "testcafe"; +import createNetworkLogger from "../../helpers/networkLogger/index.js"; +import { responseStatus } from "../../helpers/assertions/index.js"; +import createFixture from "../../helpers/createFixture/index.js"; +import { + compose, + configOverridesMain as overrides, + configOverridesAlt as alternateOverrides, + orgMainConfigMain, + debugEnabled, + consentIn, +} from "../../helpers/constants/configParts/index.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; + +const networkLogger = createNetworkLogger(); +const config = compose(orgMainConfigMain, consentIn, debugEnabled); + +createFixture({ + title: + "C7437532: `appendIdentityToUrl` can receive config overrides in command options and in `configure`", + requestHooks: [networkLogger.acquireEndpointLogs], +}); + +test.meta({ + ID: "C2592", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +test("Test C7437532: `appendIdentityToUrl` can receive config overrides in command options", async () => { + const alloy = createAlloyProxy(); + await alloy.configure(config); + // this should get an ECID + await alloy.appendIdentityToUrl({ + url: "https://example.com", + edgeConfigOverrides: overrides, + }); + + await responseStatus(networkLogger.acquireEndpointLogs.requests, [200, 207]); + await t.expect(networkLogger.acquireEndpointLogs.requests.length).eql(1); + + const request = JSON.parse( + networkLogger.acquireEndpointLogs.requests[0].request.body, + ); + + await t + .expect( + request.meta.configOverrides.com_adobe_experience_platform.datasets.event, + ) + .eql(overrides.com_adobe_experience_platform.datasets.event); + await t + .expect(request.meta.configOverrides.com_adobe_analytics.reportSuites) + .eql(overrides.com_adobe_analytics.reportSuites); + await t + .expect(request.meta.configOverrides.com_adobe_identity.idSyncContainerId) + .eql(overrides.com_adobe_identity.idSyncContainerId); + await t + .expect(request.meta.configOverrides.com_adobe_target.propertyToken) + .eql(overrides.com_adobe_target.propertyToken); +}); + +test("Test C7437532: `appendIdentityToUrl` can receive config overrides from `configure`", async () => { + const alloy = createAlloyProxy(); + await alloy.configure(compose(config, { edgeConfigOverrides: overrides })); + // this should get an ECID + await alloy.appendIdentityToUrl({ + url: "https://example.com", + }); + + await responseStatus(networkLogger.acquireEndpointLogs.requests, [200, 207]); + await t.expect(networkLogger.acquireEndpointLogs.requests.length).eql(1); + + const request = JSON.parse( + networkLogger.acquireEndpointLogs.requests[0].request.body, + ); + + await t + .expect( + request.meta.configOverrides.com_adobe_experience_platform.datasets.event, + ) + .eql(overrides.com_adobe_experience_platform.datasets.event); + await t + .expect(request.meta.configOverrides.com_adobe_analytics.reportSuites) + .eql(overrides.com_adobe_analytics.reportSuites); + await t + .expect(request.meta.configOverrides.com_adobe_identity.idSyncContainerId) + .eql(overrides.com_adobe_identity.idSyncContainerId); + await t + .expect(request.meta.configOverrides.com_adobe_target.propertyToken) + .eql(overrides.com_adobe_target.propertyToken); +}); + +test("Test C7437532: overrides from the `appendIdentityToUrl` should take precedence over the ones from `configure`", async () => { + const alloy = createAlloyProxy(); + await alloy.configure( + compose(config, { edgeConfigOverrides: alternateOverrides }), + ); + // this should get an ECID + await alloy.appendIdentityToUrl({ + url: "https://example.com", + edgeConfigOverrides: overrides, + }); + + await responseStatus(networkLogger.acquireEndpointLogs.requests, [200, 207]); + await t.expect(networkLogger.acquireEndpointLogs.requests.length).eql(1); + + const request = JSON.parse( + networkLogger.acquireEndpointLogs.requests[0].request.body, + ); + + await t + .expect( + request.meta.configOverrides.com_adobe_experience_platform.datasets.event, + ) + .eql(overrides.com_adobe_experience_platform.datasets.event); + await t + .expect(request.meta.configOverrides.com_adobe_analytics.reportSuites) + .eql(overrides.com_adobe_analytics.reportSuites); + await t + .expect(request.meta.configOverrides.com_adobe_identity.idSyncContainerId) + .eql(overrides.com_adobe_identity.idSyncContainerId); + await t + .expect(request.meta.configOverrides.com_adobe_target.propertyToken) + .eql(overrides.com_adobe_target.propertyToken); +}); + +test("Test C7437532: empty configuration overrides should not be sent to the Edge", async () => { + const alloy = createAlloyProxy(); + await alloy.configure(config); + // this should get an ECID + await alloy.appendIdentityToUrl({ + url: "https://example.com", + edgeConfigOverrides: compose(overrides, { + com_adobe_target: { + propertyToken: "", + }, + }), + }); + + await responseStatus(networkLogger.acquireEndpointLogs.requests, [200, 207]); + await t.expect(networkLogger.acquireEndpointLogs.requests.length).eql(1); + + const request = JSON.parse( + networkLogger.acquireEndpointLogs.requests[0].request.body, + ); + + await t + .expect( + request.meta.configOverrides.com_adobe_experience_platform.datasets.event, + ) + .eql(overrides.com_adobe_experience_platform.datasets.event); + await t + .expect(request.meta.configOverrides.com_adobe_analytics.reportSuites) + .eql(overrides.com_adobe_analytics.reportSuites); + await t + .expect(request.meta.configOverrides.com_adobe_identity.idSyncContainerId) + .eql(overrides.com_adobe_identity.idSyncContainerId); + await t.expect(request.meta.configOverrides.com_adobe_target).eql(undefined); +}); + +test("Test C7437532: `appendIdentityToUrl` can override the datastreamId", async () => { + const alloy = createAlloyProxy(); + await alloy.configure(config); + const { datastreamId: originalDatastreamId } = config; + const alternateDatastreamId = `${originalDatastreamId}:dev`; + await alloy.appendIdentityToUrl({ + url: "https://example.com", + edgeConfigOverrides: { + datastreamId: alternateDatastreamId, + }, + }); + + await responseStatus(networkLogger.acquireEndpointLogs.requests, [200, 207]); + await t.expect(networkLogger.acquireEndpointLogs.requests.length).eql(1); + const [request] = networkLogger.acquireEndpointLogs.requests; + await t.expect(request.request.url).contains(alternateDatastreamId); + const body = JSON.parse(request.request.body); + await t + .expect(body.meta.sdkConfig.datastream.original) + .eql(originalDatastreamId); +}); diff --git a/packages/browser/test/functional/specs/Config Overrides/C7437533.js b/packages/browser/test/functional/specs/Config Overrides/C7437533.js new file mode 100644 index 000000000..812990e25 --- /dev/null +++ b/packages/browser/test/functional/specs/Config Overrides/C7437533.js @@ -0,0 +1,200 @@ +/* +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 } from "testcafe"; +import createNetworkLogger from "../../helpers/networkLogger/index.js"; +import { responseStatus } from "../../helpers/assertions/index.js"; +import createFixture from "../../helpers/createFixture/index.js"; +import { + compose, + configOverridesMain as overrides, + configOverridesAlt as alternateOverrides, + orgMainConfigMain, + debugEnabled, +} from "../../helpers/constants/configParts/index.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; +import { IAB_CONSENT_IN } from "../../helpers/constants/consent.js"; + +const networkLogger = createNetworkLogger(); +const config = compose(orgMainConfigMain, debugEnabled); + +createFixture({ + title: + "C7437533: `setConsent` can receive config overrides in command options and in `configure`", + requestHooks: [networkLogger.setConsentEndpointLogs], +}); + +test.meta({ + ID: "C2592", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +test("Test C7437533: `setConsent` can receive config overrides in command options", async () => { + const alloy = createAlloyProxy(); + await alloy.configure(config); + await alloy.setConsent( + compose(IAB_CONSENT_IN, { edgeConfigOverrides: overrides }), + ); + + await responseStatus( + networkLogger.setConsentEndpointLogs.requests, + [200, 207], + ); + await t.expect(networkLogger.setConsentEndpointLogs.requests.length).eql(1); + + const request = JSON.parse( + networkLogger.setConsentEndpointLogs.requests[0].request.body, + ); + + await t + .expect( + request.meta.configOverrides.com_adobe_experience_platform.datasets.event, + ) + .eql(overrides.com_adobe_experience_platform.datasets.event); + await t + .expect(request.meta.configOverrides.com_adobe_analytics.reportSuites) + .eql(overrides.com_adobe_analytics.reportSuites); + await t + .expect(request.meta.configOverrides.com_adobe_identity.idSyncContainerId) + .eql(overrides.com_adobe_identity.idSyncContainerId); + await t + .expect(request.meta.configOverrides.com_adobe_target.propertyToken) + .eql(overrides.com_adobe_target.propertyToken); +}); + +test("Test C7437533: `setConsent` can receive config overrides from `configure`", async () => { + const alloy = createAlloyProxy(); + await alloy.configure(compose(config, { edgeConfigOverrides: overrides })); + await alloy.setConsent(IAB_CONSENT_IN); + + await responseStatus( + networkLogger.setConsentEndpointLogs.requests, + [200, 207], + ); + await t.expect(networkLogger.setConsentEndpointLogs.requests.length).eql(1); + + const request = JSON.parse( + networkLogger.setConsentEndpointLogs.requests[0].request.body, + ); + + await t + .expect( + request.meta.configOverrides.com_adobe_experience_platform.datasets.event, + ) + .eql(overrides.com_adobe_experience_platform.datasets.event); + await t + .expect(request.meta.configOverrides.com_adobe_analytics.reportSuites) + .eql(overrides.com_adobe_analytics.reportSuites); + await t + .expect(request.meta.configOverrides.com_adobe_identity.idSyncContainerId) + .eql(overrides.com_adobe_identity.idSyncContainerId); + await t + .expect(request.meta.configOverrides.com_adobe_target.propertyToken) + .eql(overrides.com_adobe_target.propertyToken); +}); + +test("Test C7437533: overrides from `setConsent` should take precedence over the ones from `configure`", async () => { + const alloy = createAlloyProxy(); + await alloy.configure(compose(config, { edgeConfigOverrides: overrides })); + await alloy.setConsent(IAB_CONSENT_IN, { + edgeConfigOverrides: alternateOverrides, + }); + + await responseStatus( + networkLogger.setConsentEndpointLogs.requests, + [200, 207], + ); + await t.expect(networkLogger.setConsentEndpointLogs.requests.length).eql(1); + + const request = JSON.parse( + networkLogger.setConsentEndpointLogs.requests[0].request.body, + ); + + await t + .expect( + request.meta.configOverrides.com_adobe_experience_platform.datasets.event, + ) + .eql(overrides.com_adobe_experience_platform.datasets.event); + await t + .expect(request.meta.configOverrides.com_adobe_analytics.reportSuites) + .eql(overrides.com_adobe_analytics.reportSuites); + await t + .expect(request.meta.configOverrides.com_adobe_identity.idSyncContainerId) + .eql(overrides.com_adobe_identity.idSyncContainerId); + await t + .expect(request.meta.configOverrides.com_adobe_target.propertyToken) + .eql(overrides.com_adobe_target.propertyToken); +}); + +test("Test C7437533: empty configuration overrides should not be sent to the Edge", async () => { + const alloy = createAlloyProxy(); + await alloy.configure(config); + await alloy.setConsent( + compose(IAB_CONSENT_IN, { + edgeConfigOverrides: compose(overrides, { + com_adobe_target: { + propertyToken: "", + }, + }), + }), + ); + + await responseStatus( + networkLogger.setConsentEndpointLogs.requests, + [200, 207], + ); + await t.expect(networkLogger.setConsentEndpointLogs.requests.length).eql(1); + + const request = JSON.parse( + networkLogger.setConsentEndpointLogs.requests[0].request.body, + ); + + await t + .expect( + request.meta.configOverrides.com_adobe_experience_platform.datasets.event, + ) + .eql(overrides.com_adobe_experience_platform.datasets.event); + await t + .expect(request.meta.configOverrides.com_adobe_analytics.reportSuites) + .eql(overrides.com_adobe_analytics.reportSuites); + await t + .expect(request.meta.configOverrides.com_adobe_identity.idSyncContainerId) + .eql(overrides.com_adobe_identity.idSyncContainerId); + await t.expect(request.meta.configOverrides.com_adobe_target).eql(undefined); +}); + +test("Test C7437533: `setConsent` can override the datastreamId", async () => { + const alloy = createAlloyProxy(); + await alloy.configure(config); + const { datastreamId: originalDatastreamId } = config; + const alternateDatastreamId = `${originalDatastreamId}:dev`; + await alloy.setConsent( + compose(IAB_CONSENT_IN, { + edgeConfigOverrides: { + datastreamId: alternateDatastreamId, + }, + }), + ); + + await responseStatus( + networkLogger.setConsentEndpointLogs.requests, + [200, 207], + ); + await t.expect(networkLogger.setConsentEndpointLogs.requests.length).eql(1); + const [request] = networkLogger.setConsentEndpointLogs.requests; + await t.expect(request.request.url).contains(alternateDatastreamId); + + const body = JSON.parse(request.request.body); + await t + .expect(body.meta.sdkConfig.datastream.original) + .eql(originalDatastreamId); +}); diff --git a/packages/browser/test/functional/specs/Consent/C14404.js b/packages/browser/test/functional/specs/Consent/C14404.js new file mode 100644 index 000000000..7b04a0725 --- /dev/null +++ b/packages/browser/test/functional/specs/Consent/C14404.js @@ -0,0 +1,64 @@ +/* +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 } from "testcafe"; +import createFixture from "../../helpers/createFixture/index.js"; +import createNetworkLogger from "../../helpers/networkLogger/index.js"; + +import { + compose, + orgMainConfigMain, + consentPending, + debugEnabled, +} from "../../helpers/constants/configParts/index.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; +import { CONSENT_OUT, CONSENT_IN } from "../../helpers/constants/consent.js"; +import cookies from "../../helpers/cookies.js"; +import { MAIN_CONSENT_COOKIE_NAME } from "../../helpers/constants/cookies.js"; + +const config = compose(orgMainConfigMain, consentPending, debugEnabled); + +const networkLogger = createNetworkLogger(); + +createFixture({ + title: + "C14404: User cannot consent to all purposes after consenting to no purposes", + requestHooks: [ + networkLogger.edgeEndpointLogs, + networkLogger.setConsentEndpointLogs, + ], +}); + +test.meta({ + ID: "C14404", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +test("Test C14404: User can consent to all purposes after consenting to no purposes", async () => { + const alloy = createAlloyProxy(); + await alloy.configure(config); + await alloy.setConsent(CONSENT_OUT); + + // set consent back to in for the same user + await alloy.setConsent(CONSENT_IN); + + await t.expect(networkLogger.setConsentEndpointLogs.requests.length).eql(2); + + const consentCookieValue = await cookies.get(MAIN_CONSENT_COOKIE_NAME); + + await t.expect(consentCookieValue).ok("No consent cookie found."); + await t.expect(consentCookieValue).eql("general=in"); + + // make sure event goes out + await alloy.sendEvent(); + await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(1); +}); diff --git a/packages/browser/test/functional/specs/Consent/C14405.js b/packages/browser/test/functional/specs/Consent/C14405.js new file mode 100644 index 000000000..d9bfc3113 --- /dev/null +++ b/packages/browser/test/functional/specs/Consent/C14405.js @@ -0,0 +1,50 @@ +/* +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 createFixture from "../../helpers/createFixture/index.js"; +import createNetworkLogger from "../../helpers/networkLogger/index.js"; + +import { + compose, + orgMainConfigMain, + consentPending, + debugEnabled, +} from "../../helpers/constants/configParts/index.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; + +import { CONSENT_IN } from "../../helpers/constants/consent.js"; + +const config = compose(orgMainConfigMain, consentPending, debugEnabled); + +const networkLogger = createNetworkLogger(); + +createFixture({ + title: "C14405: Unidentified user can consent to all purposes", + requestHooks: [networkLogger.edgeEndpointLogs], +}); + +test.meta({ + ID: "C14405", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +test("Test C14405: Unidentified user can consent to all purposes", async (t) => { + const alloy = createAlloyProxy(); + await alloy.configure(config); + await alloy.setConsent(CONSENT_IN); + await alloy.sendEvent(); + await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(1); + const request = networkLogger.edgeEndpointLogs.requests[0].request.body; + await t + .expect(request) + .contains('"name":"https://ns.adobe.com/experience/alloy"'); +}); diff --git a/packages/browser/test/functional/specs/Consent/C14406.js b/packages/browser/test/functional/specs/Consent/C14406.js new file mode 100644 index 000000000..83f75f1ba --- /dev/null +++ b/packages/browser/test/functional/specs/Consent/C14406.js @@ -0,0 +1,48 @@ +/* +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 createFixture from "../../helpers/createFixture/index.js"; +import createNetworkLogger from "../../helpers/networkLogger/index.js"; +import { + compose, + orgMainConfigMain, + consentPending, + debugEnabled, +} from "../../helpers/constants/configParts/index.js"; +import createConsoleLogger from "../../helpers/consoleLogger/index.js"; + +import { CONSENT_OUT } from "../../helpers/constants/consent.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; + +const config = compose(orgMainConfigMain, consentPending, debugEnabled); + +const networkLogger = createNetworkLogger(); + +createFixture({ + title: "C14406: Unidentified user can consent to no purposes", + requestHooks: [networkLogger.edgeEndpointLogs], +}); + +test.meta({ + ID: "C14406", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +test("Test C14406: Unidentified user can consent to no purposes", async (t) => { + const logger = await createConsoleLogger(); + const alloy = createAlloyProxy(); + await alloy.configure(config); + await alloy.setConsent(CONSENT_OUT); + await alloy.sendEvent(); + await logger.warn.expectMessageMatching(/user declined consent/); + await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(0); +}); diff --git a/packages/browser/test/functional/specs/Consent/C14407.js b/packages/browser/test/functional/specs/Consent/C14407.js new file mode 100644 index 000000000..4cf8d589b --- /dev/null +++ b/packages/browser/test/functional/specs/Consent/C14407.js @@ -0,0 +1,48 @@ +/* +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 } from "testcafe"; +import createNetworkLogger from "../../helpers/networkLogger/index.js"; +import createFixture from "../../helpers/createFixture/index.js"; +import { CONSENT_IN } from "../../helpers/constants/consent.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; +import reloadPage from "../../helpers/reloadPage.js"; + +const networkLogger = createNetworkLogger(); + +createFixture({ + title: "C14407 - Consenting to all purposes should be persisted.", + requestHooks: [networkLogger.edgeEndpointLogs], +}); + +test.meta({ + ID: "C14407", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +const config = { + datastreamId: "9999999", + orgId: "53A16ACB5CC1D3760A495C99@AdobeOrg", + defaultConsent: "pending", + idMigrationEnabled: false, + debugEnabled: true, +}; + +test("C14407 - Consenting to all purposes should be persisted.", async () => { + const alloy = createAlloyProxy(); + await alloy.configure(config); + await alloy.setConsent(CONSENT_IN); + await reloadPage(); + await alloy.configure(config); + await alloy.sendEvent(); + await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(1); +}); diff --git a/packages/browser/test/functional/specs/Consent/C14409.js b/packages/browser/test/functional/specs/Consent/C14409.js new file mode 100644 index 000000000..e38051944 --- /dev/null +++ b/packages/browser/test/functional/specs/Consent/C14409.js @@ -0,0 +1,55 @@ +/* +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 } from "testcafe"; +import createNetworkLogger from "../../helpers/networkLogger/index.js"; +import createFixture from "../../helpers/createFixture/index.js"; +import createConsoleLogger from "../../helpers/consoleLogger/index.js"; +import { CONSENT_OUT } from "../../helpers/constants/consent.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; +import reloadPage from "../../helpers/reloadPage.js"; + +const networkLogger = createNetworkLogger(); + +createFixture({ + title: "C14409 - Consenting to no purposes should be persisted.", + requestHooks: [networkLogger.edgeEndpointLogs], +}); + +test.meta({ + ID: "C14409", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +const config = { + datastreamId: "9999999", + orgId: "53A16ACB5CC1D3760A495C99@AdobeOrg", + defaultConsent: "pending", + idMigrationEnabled: false, + debugEnabled: true, +}; + +test("C14409 - Consenting to no purposes should be persisted.", async () => { + const alloy = createAlloyProxy(); + await alloy.configure(config); + await alloy.setConsent(CONSENT_OUT); + // Reload page and reconfigure alloy + // [TODO] Navigate to a different subdomain when it is available + // https://github.com/DevExpress/testcafe/blob/a4f6a4ac3627ebeb29b344ed3a1793627dd87909/docs/articles/documentation/test-api/actions/navigate.md + await reloadPage(); + + await alloy.configure(config); + const logger = await createConsoleLogger(); + await alloy.sendEvent(); + await logger.warn.expectMessageMatching(/user declined consent/); + await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(0); +}); diff --git a/packages/browser/test/functional/specs/Consent/C14410.js b/packages/browser/test/functional/specs/Consent/C14410.js new file mode 100644 index 000000000..6e0319f7d --- /dev/null +++ b/packages/browser/test/functional/specs/Consent/C14410.js @@ -0,0 +1,72 @@ +/* +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 createFixture from "../../helpers/createFixture/index.js"; +import orgMainConfigMain from "../../helpers/constants/configParts/orgMainConfigMain.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; +import { CONSENT_IN } from "../../helpers/constants/consent.js"; + +createFixture({ + title: + 'C14410: Setting consent for other purposes, or to other values than "in" or "out" should fail', +}); + +test.meta({ + ID: "C14410", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +// This test was originally designed to be done using one test case. When the configure command fails +// from the validation to make sure that only once instance has a particular orgId, the validation +// state isn't reset, so when I had this all in one test, the third part here was failing because +// an instance was already configured with that orgId. + +test("Test C14410: Configuring default consent to 'unknown' fails", async (t) => { + const alloy = createAlloyProxy(); + const errorMessage = await alloy.configureErrorMessage({ + defaultConsent: "unknown", + ...orgMainConfigMain, + }); + await t + .expect(errorMessage) + .ok("Expected the configure command to be rejected"); + await t.expect(errorMessage).contains("'defaultConsent':"); + await t + .expect(errorMessage) + .contains( + `Expected one of these values: ["in","out","pending"], but got "unknown"`, + ); +}); + +test("Test C14410: Setting consent for unknown purposes fails", async (t) => { + const alloy = createAlloyProxy(); + await alloy.configure({ + defaultConsent: "pending", + ...orgMainConfigMain, + }); + const errorMessage = alloy.setConsentErrorMessage({ + consent: [ + { standard: "Adobe", version: "1.0", value: { analytics: "in" } }, + ], + }); + await t + .expect(errorMessage) + .ok("Expected the setConsent command to be rejected"); + await t + .expect(errorMessage) + .contains("The server responded with a status code 400") + .expect(errorMessage) + .contains("EXEG-0102-400"); + + // make sure we can call it again with the correct values + await alloy.setConsent(CONSENT_IN); +}); diff --git a/packages/browser/test/functional/specs/Consent/C14411.js b/packages/browser/test/functional/specs/Consent/C14411.js new file mode 100644 index 000000000..3251b1079 --- /dev/null +++ b/packages/browser/test/functional/specs/Consent/C14411.js @@ -0,0 +1,55 @@ +/* +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 createFixture from "../../helpers/createFixture/index.js"; +import { + compose, + orgMainConfigMain, + consentPending, +} from "../../helpers/constants/configParts/index.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; +import { CONSENT_OUT } from "../../helpers/constants/consent.js"; +import { MAIN_CONSENT_COOKIE_NAME } from "../../helpers/constants/cookies.js"; +import cookies from "../../helpers/cookies.js"; +import reloadPage from "../../helpers/reloadPage.js"; + +const config = compose(orgMainConfigMain, consentPending); + +createFixture({ + title: "C14411: User consents to no purposes after consenting to no purposes", +}); + +test.meta({ + ID: "C14411", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +test("Test C14411: User consents to no purposes after consenting to no purposes with cache", async () => { + const alloy = createAlloyProxy(); + await alloy.configure(config); + await alloy.setConsent(CONSENT_OUT); + // make sure this doesn't throw an error + await alloy.setConsent(CONSENT_OUT); +}); + +test("Test C14411: User consents to no purposes after consenting to no purposes without cache", async () => { + const alloy = createAlloyProxy(); + await alloy.configure(config); + await alloy.setConsent(CONSENT_OUT); + + await reloadPage(); + await cookies.remove(MAIN_CONSENT_COOKIE_NAME); + + await alloy.configure(config); + // make sure this doesn't throw an error + await alloy.setConsent(CONSENT_OUT); +}); diff --git a/packages/browser/test/functional/specs/Consent/C14414.js b/packages/browser/test/functional/specs/Consent/C14414.js new file mode 100644 index 000000000..90392f785 --- /dev/null +++ b/packages/browser/test/functional/specs/Consent/C14414.js @@ -0,0 +1,68 @@ +/* +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 createFixture from "../../helpers/createFixture/index.js"; +import { + compose, + orgMainConfigMain, + consentPending, + debugEnabled, +} from "../../helpers/constants/configParts/index.js"; +import { CONSENT_IN, CONSENT_OUT } from "../../helpers/constants/consent.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; +import createNetworkLogger from "../../helpers/networkLogger/index.js"; +import SequentialHook from "../../helpers/requestHooks/sequentialHook.js"; + +const config = compose(orgMainConfigMain, consentPending, debugEnabled); + +const networkLogger = createNetworkLogger(); + +createFixture({ + title: "C14414: Requests are queued while consent changes are pending", + requestHooks: [networkLogger.edgeEndpointLogs], +}); + +test.meta({ + ID: "C14414", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +test + .before(async (t) => { + // Create the hook here so that it is only used for one test run. + t.ctx.setConsentHook = new SequentialHook(/v1\/privacy\/set-consent\?/); + await t.addRequestHooks(t.ctx.setConsentHook); + }) + .after(async (t) => { + await t.removeRequestHooks(t.ctx.setConsentHook); + })( + "Test C14414: Requests are queued while consent changes are pending", + async (t) => { + const alloy = createAlloyProxy(); + await alloy.configure(config); + const setConsentResponse1 = await alloy.setConsentAsync(CONSENT_IN); + const setConsentResponse2 = await alloy.setConsentAsync(CONSENT_OUT); + await alloy.sendEvent(); + + // make sure there are no errors returned from the setConsent requests + await setConsentResponse1.result; + await setConsentResponse2.result; + + // make sure the event was not sent + await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(0); + + await t + .expect(t.ctx.setConsentHook.haveRequestsBeenSequential()) + .ok("Set-consent requests were not sequential"); + await t.expect(t.ctx.setConsentHook.getNumRequests()).eql(2); + }, +); diff --git a/packages/browser/test/functional/specs/Consent/C1472433.js b/packages/browser/test/functional/specs/Consent/C1472433.js new file mode 100644 index 000000000..691972d8a --- /dev/null +++ b/packages/browser/test/functional/specs/Consent/C1472433.js @@ -0,0 +1,59 @@ +/* +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 } from "testcafe"; +import createFixture from "../../helpers/createFixture/index.js"; +import createNetworkLogger from "../../helpers/networkLogger/index.js"; +import orgMainConfigMain from "../../helpers/constants/configParts/orgMainConfigMain.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; +import reloadPage from "../../helpers/reloadPage.js"; +import { ADOBE2_IN } from "../../helpers/constants/consent.js"; + +const networkLogger = createNetworkLogger(); + +createFixture({ + title: "C1472433: Set-consent is not called when consent is the same", + requestHooks: [ + networkLogger.setConsentEndpointLogs, + networkLogger.edgeInteractEndpointLogs, + ], +}); + +test.meta({ + ID: "C1472433", + SEVERITY: "P0", + TEST_RUN: "REGRESSION", +}); + +const configuration = { + defaultConsent: "pending", + ...orgMainConfigMain, +}; + +test("C1472433 - Set-consent is not called when consent is the same", async () => { + // set consent to in + const alloy = createAlloyProxy(); + await alloy.configure(configuration); + await alloy.setConsent(ADOBE2_IN); + await t.expect(networkLogger.setConsentEndpointLogs.requests.length).eql(1); + + // reload the page to make sure the hashes are stored + await reloadPage(); + await alloy.configure(configuration); + + // send an event which should go out immediately + await alloy.sendEvent(); + await t.expect(networkLogger.edgeInteractEndpointLogs.requests.length).eql(1); + + // set the consent to in again, and make sure an edge request isn't generated. + await alloy.setConsent(ADOBE2_IN); + await t.expect(networkLogger.setConsentEndpointLogs.requests.length).eql(1); +}); diff --git a/packages/browser/test/functional/specs/Consent/C1472434.js b/packages/browser/test/functional/specs/Consent/C1472434.js new file mode 100644 index 000000000..975e55c3c --- /dev/null +++ b/packages/browser/test/functional/specs/Consent/C1472434.js @@ -0,0 +1,59 @@ +/* +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 } from "testcafe"; +import createFixture from "../../helpers/createFixture/index.js"; +import createNetworkLogger from "../../helpers/networkLogger/index.js"; +import orgMainConfigMain from "../../helpers/constants/configParts/orgMainConfigMain.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; +import reloadPage from "../../helpers/reloadPage.js"; +import { ADOBE2_IN, ADOBE2_OUT } from "../../helpers/constants/consent.js"; + +const networkLogger = createNetworkLogger(); + +createFixture({ + title: "C1472434: Set-consent is called when consent is different", + requestHooks: [ + networkLogger.setConsentEndpointLogs, + networkLogger.edgeInteractEndpointLogs, + ], +}); + +test.meta({ + ID: "C1472434", + SEVERITY: "P0", + TEST_RUN: "REGRESSION", +}); + +const configuration = { + defaultConsent: "pending", + ...orgMainConfigMain, +}; + +test("C1472434: Set-consent is called when consent is different", async () => { + // set consent to in + const alloy = createAlloyProxy(); + await alloy.configure(configuration); + await alloy.setConsent(ADOBE2_IN); + await t.expect(networkLogger.setConsentEndpointLogs.requests.length).eql(1); + + // reload the page to make sure the hashes are stored and not just in memory + await reloadPage(); + await alloy.configure(configuration); + + // send an event which should go out immediately + await alloy.sendEvent(); + await t.expect(networkLogger.edgeInteractEndpointLogs.requests.length).eql(1); + + // set the consent on Alloy, and make sure it generates a new edge request + await alloy.setConsent(ADOBE2_OUT); + await t.expect(networkLogger.setConsentEndpointLogs.requests.length).eql(2); +}); diff --git a/packages/browser/test/functional/specs/Consent/C1472435.js b/packages/browser/test/functional/specs/Consent/C1472435.js new file mode 100644 index 000000000..f59454002 --- /dev/null +++ b/packages/browser/test/functional/specs/Consent/C1472435.js @@ -0,0 +1,73 @@ +/* +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 } from "testcafe"; +import createFixture from "../../helpers/createFixture/index.js"; +import createNetworkLogger from "../../helpers/networkLogger/index.js"; +import orgMainConfigMain from "../../helpers/constants/configParts/orgMainConfigMain.js"; +import reloadPage from "../../helpers/reloadPage.js"; +import flushPromiseChains from "../../helpers/flushPromiseChains.js"; +import cookies from "../../helpers/cookies.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; +import { + LEGACY_IDENTITY_COOKIE_NAME, + MAIN_IDENTITY_COOKIE_NAME, +} from "../../helpers/constants/cookies.js"; +import { ADOBE2_IN } from "../../helpers/constants/consent.js"; + +const networkLogger = createNetworkLogger(); + +createFixture({ + title: + "C1472435: Set-consent is called when identity cookie is missing even though consent is the same", + requestHooks: [ + networkLogger.setConsentEndpointLogs, + networkLogger.edgeInteractEndpointLogs, + ], +}); + +test.meta({ + ID: "C1472435", + SEVERITY: "P0", + TEST_RUN: "REGRESSION", +}); + +const configuration = { + defaultConsent: "pending", + ...orgMainConfigMain, +}; + +test("C1472435: Set-consent is called when identity cookie is missing even though consent is the same", async () => { + // set consent to in + const alloy = createAlloyProxy(); + await alloy.configure(configuration); + await alloy.setConsent(ADOBE2_IN); + await t.expect(networkLogger.setConsentEndpointLogs.requests.length).eql(1); + + // delete identity cookie, and reload + await reloadPage(); + await cookies.remove(MAIN_IDENTITY_COOKIE_NAME); + await cookies.remove(LEGACY_IDENTITY_COOKIE_NAME); + await alloy.configure(configuration); + + // try to send an event, but it should be queued + const sendEventResponse = await alloy.sendEventAsync(); + await flushPromiseChains(); + await t.expect(networkLogger.edgeInteractEndpointLogs.requests.length).eql(0); + + // set the consent to IN + await alloy.setConsent(ADOBE2_IN); + await t.expect(networkLogger.setConsentEndpointLogs.requests.length).eql(2); + + // make sure the event goes out + await sendEventResponse.result; + await t.expect(networkLogger.edgeInteractEndpointLogs.requests.length).eql(1); +}); diff --git a/packages/browser/test/functional/specs/Consent/C1472436.js b/packages/browser/test/functional/specs/Consent/C1472436.js new file mode 100644 index 000000000..eb94ea742 --- /dev/null +++ b/packages/browser/test/functional/specs/Consent/C1472436.js @@ -0,0 +1,70 @@ +/* +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 } from "testcafe"; +import createFixture from "../../helpers/createFixture/index.js"; +import createNetworkLogger from "../../helpers/networkLogger/index.js"; +import orgMainConfigMain from "../../helpers/constants/configParts/orgMainConfigMain.js"; +import reloadPage from "../../helpers/reloadPage.js"; +import flushPromiseChains from "../../helpers/flushPromiseChains.js"; +import cookies from "../../helpers/cookies.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; +import { ADOBE2_IN } from "../../helpers/constants/consent.js"; +import { MAIN_CONSENT_COOKIE_NAME } from "../../helpers/constants/cookies.js"; + +const networkLogger = createNetworkLogger(); + +createFixture({ + title: + "C1472436: Set-consent is called when consent cookie is missing even though consent is the same", + requestHooks: [ + networkLogger.setConsentEndpointLogs, + networkLogger.edgeInteractEndpointLogs, + ], +}); + +test.meta({ + ID: "C1472436", + SEVERITY: "P0", + TEST_RUN: "REGRESSION", +}); + +const configuration = { + defaultConsent: "pending", + debugEnabled: true, + ...orgMainConfigMain, +}; + +test("C1472436: Set-consent is called when consent cookie is missing even though consent is the same", async () => { + // set consent to in + const alloy = createAlloyProxy(); + await alloy.configure(configuration); + await alloy.setConsent(ADOBE2_IN); + await t.expect(networkLogger.setConsentEndpointLogs.requests.length).eql(1); + + // delete consent cookie, and reload + await reloadPage(); + await cookies.remove(MAIN_CONSENT_COOKIE_NAME); + await alloy.configure(configuration); + + // try to send an event, but it should be queued + const sendEventResponse = await alloy.sendEventAsync(); + await flushPromiseChains(); + await t.expect(networkLogger.edgeInteractEndpointLogs.requests.length).eql(0); + + // set the consent to IN + await alloy.setConsent(ADOBE2_IN); + await t.expect(networkLogger.setConsentEndpointLogs.requests.length).eql(2); + + // make sure the event goes out + await sendEventResponse.result; + await t.expect(networkLogger.edgeInteractEndpointLogs.requests.length).eql(1); +}); diff --git a/packages/browser/test/functional/specs/Consent/C1472437.js b/packages/browser/test/functional/specs/Consent/C1472437.js new file mode 100644 index 000000000..092eeee48 --- /dev/null +++ b/packages/browser/test/functional/specs/Consent/C1472437.js @@ -0,0 +1,58 @@ +/* +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 } from "testcafe"; +import createFixture from "../../helpers/createFixture/index.js"; +import createNetworkLogger from "../../helpers/networkLogger/index.js"; +import orgMainConfigMain from "../../helpers/constants/configParts/orgMainConfigMain.js"; +import flushPromiseChains from "../../helpers/flushPromiseChains.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; +import { ADOBE2_IN } from "../../helpers/constants/consent.js"; + +const networkLogger = createNetworkLogger(); + +createFixture({ + title: "C1472437: Adobe consent version 2.0 is translated to general=in", + requestHooks: [ + networkLogger.setConsentEndpointLogs, + networkLogger.edgeInteractEndpointLogs, + ], +}); + +test.meta({ + ID: "C1472437", + SEVERITY: "P0", + TEST_RUN: "REGRESSION", +}); + +const configuration = { + defaultConsent: "pending", + ...orgMainConfigMain, +}; + +test("C1472437: Adobe consent version 2.0 is translated to general=in", async () => { + // setup alloy + const alloy = createAlloyProxy(); + await alloy.configure(configuration); + + // try to send an event, but it should be queued + const sendEventResponse = await alloy.sendEventAsync(); + await flushPromiseChains(); + await t.expect(networkLogger.edgeInteractEndpointLogs.requests.length).eql(0); + + // set the consent to IN + await alloy.setConsent(ADOBE2_IN); + await t.expect(networkLogger.setConsentEndpointLogs.requests.length).eql(1); + + // make sure the event goes out + await sendEventResponse.result; + await t.expect(networkLogger.edgeInteractEndpointLogs.requests.length).eql(1); +}); diff --git a/packages/browser/test/functional/specs/Consent/C1472438.js b/packages/browser/test/functional/specs/Consent/C1472438.js new file mode 100644 index 000000000..d4dd14e6b --- /dev/null +++ b/packages/browser/test/functional/specs/Consent/C1472438.js @@ -0,0 +1,58 @@ +/* +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 } from "testcafe"; +import createFixture from "../../helpers/createFixture/index.js"; +import createNetworkLogger from "../../helpers/networkLogger/index.js"; +import orgMainConfigMain from "../../helpers/constants/configParts/orgMainConfigMain.js"; +import flushPromiseChains from "../../helpers/flushPromiseChains.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; +import { ADOBE2_OUT } from "../../helpers/constants/consent.js"; + +const networkLogger = createNetworkLogger(); + +createFixture({ + title: "C1472438: Adobe consent version 2.0 is translated to general=out", + requestHooks: [ + networkLogger.setConsentEndpointLogs, + networkLogger.edgeInteractEndpointLogs, + ], +}); + +test.meta({ + ID: "C1472438", + SEVERITY: "P0", + TEST_RUN: "REGRESSION", +}); + +const configuration = { + defaultConsent: "pending", + ...orgMainConfigMain, +}; + +test("C1472438: Adobe consent version 2.0 is translated to general=out", async () => { + // setup alloy + const alloy = createAlloyProxy(); + await alloy.configure(configuration); + + // try to send an event, but it should be queued + const sendEventResponse = await alloy.sendEventAsync(); + await flushPromiseChains(); + await t.expect(networkLogger.edgeInteractEndpointLogs.requests.length).eql(0); + + // set the consent to OUT + await alloy.setConsent(ADOBE2_OUT); + await t.expect(networkLogger.setConsentEndpointLogs.requests.length).eql(1); + + // make sure the event does not go out + await sendEventResponse.result; + await t.expect(networkLogger.edgeInteractEndpointLogs.requests.length).eql(0); +}); diff --git a/packages/browser/test/functional/specs/Consent/C1576777.js b/packages/browser/test/functional/specs/Consent/C1576777.js new file mode 100644 index 000000000..f8d84df7b --- /dev/null +++ b/packages/browser/test/functional/specs/Consent/C1576777.js @@ -0,0 +1,70 @@ +/* +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 } from "testcafe"; +import createFixture from "../../helpers/createFixture/index.js"; +import createNetworkLogger from "../../helpers/networkLogger/index.js"; +import orgMainConfigMain from "../../helpers/constants/configParts/orgMainConfigMain.js"; +import reloadPage from "../../helpers/reloadPage.js"; +import cookies from "../../helpers/cookies.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; +import { + LEGACY_IDENTITY_COOKIE_NAME, + MAIN_IDENTITY_COOKIE_NAME, +} from "../../helpers/constants/cookies.js"; +import { ADOBE2_OUT } from "../../helpers/constants/consent.js"; + +const networkLogger = createNetworkLogger(); + +createFixture({ + title: "C1576777: When identity cookie is missing, stored consent is cleared", + requestHooks: [ + networkLogger.setConsentEndpointLogs, + networkLogger.edgeInteractEndpointLogs, + ], +}); + +test.meta({ + ID: "C1576777", + SEVERITY: "P0", + TEST_RUN: "REGRESSION", +}); + +const configuration = { + defaultConsent: "in", + debugEnabled: true, + idMigrationEnabled: true, + thirdPartyCookiesEnabled: false, + ...orgMainConfigMain, +}; + +test.skip("C1576777: When identity cookie is missing, stored consent is cleared", async () => { + // set consent to out + const alloy = createAlloyProxy(); + await alloy.configure(configuration); + await alloy.setConsent(ADOBE2_OUT); + + // delete identity cookie, and reload + await reloadPage(); + await cookies.remove(MAIN_IDENTITY_COOKIE_NAME); + await cookies.remove(LEGACY_IDENTITY_COOKIE_NAME); + await alloy.configure(configuration); + + // try to send an event it should go out since the stored consent should be cleared + await alloy.sendEvent(); + + // reload again because now we have an identity cookie + await reloadPage(); + await alloy.configure(configuration); + await alloy.sendEvent(); + + await t.expect(networkLogger.edgeInteractEndpointLogs.requests.length).eql(2); +}); diff --git a/packages/browser/test/functional/specs/Consent/C1631712.js b/packages/browser/test/functional/specs/Consent/C1631712.js new file mode 100644 index 000000000..43062b652 --- /dev/null +++ b/packages/browser/test/functional/specs/Consent/C1631712.js @@ -0,0 +1,60 @@ +/* +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 createFixture from "../../helpers/createFixture/index.js"; +import { + compose, + orgMainConfigMain, + debugEnabled, +} from "../../helpers/constants/configParts/index.js"; +import { CONSENT_IN } from "../../helpers/constants/consent.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; +import createNetworkLogger from "../../helpers/networkLogger/index.js"; +import flushPromiseChains from "../../helpers/flushPromiseChains.js"; +import createConsoleLogger from "../../helpers/consoleLogger/index.js"; + +const config = compose( + orgMainConfigMain, + { defaultConsent: "out" }, + debugEnabled, +); + +const networkLogger = createNetworkLogger(); + +createFixture({ + title: "C1631712: Requests are dropped when default consent is out", + requestHooks: [networkLogger.edgeEndpointLogs], +}); + +test.meta({ + ID: "C1631712", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +test("Test C1631712: Requests are dropped when default consent is out", async (t) => { + const alloy = createAlloyProxy(); + await alloy.configure(config); + const logger = await createConsoleLogger(); + + const result = await alloy.sendEvent(); + await t.expect(result).eql({}); + await logger.warn.expectMessageMatching( + /No consent preferences have been set./, + ); + + await alloy.setConsent(CONSENT_IN); + await flushPromiseChains(); + await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(0); + + await alloy.sendEvent(); + await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(1); +}); diff --git a/packages/browser/test/functional/specs/Consent/C225953.js b/packages/browser/test/functional/specs/Consent/C225953.js new file mode 100644 index 000000000..177033644 --- /dev/null +++ b/packages/browser/test/functional/specs/Consent/C225953.js @@ -0,0 +1,54 @@ +/* +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 createFixture from "../../helpers/createFixture/index.js"; +import createNetworkLogger from "../../helpers/networkLogger/index.js"; +import { responseStatus } from "../../helpers/assertions/index.js"; + +import { + compose, + orgMainConfigMain, + consentPending, + debugEnabled, +} from "../../helpers/constants/configParts/index.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; +import { CONSENT_IN } from "../../helpers/constants/consent.js"; + +const config = compose(orgMainConfigMain, consentPending, debugEnabled); + +const networkLogger = createNetworkLogger(); + +createFixture({ + title: "C225953: Identity map can be sent on a setConsent command", + requestHooks: [networkLogger.edgeEndpointLogs], +}); + +test.meta({ + ID: "C225953", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +test("Test C225953: Identity map can be sent on a setConsent command", async () => { + const alloy = createAlloyProxy(); + await alloy.configure(config); + await alloy.setConsent({ + identityMap: { + HYP: [ + { + id: "id123", + }, + ], + }, + consent: CONSENT_IN.consent, + }); + await responseStatus(networkLogger.edgeEndpointLogs.requests, [200, 207]); +}); diff --git a/packages/browser/test/functional/specs/Consent/C25148.js b/packages/browser/test/functional/specs/Consent/C25148.js new file mode 100644 index 000000000..634c00234 --- /dev/null +++ b/packages/browser/test/functional/specs/Consent/C25148.js @@ -0,0 +1,60 @@ +/* +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 } from "testcafe"; +import createNetworkLogger from "../../helpers/networkLogger/index.js"; +import createFixture from "../../helpers/createFixture/index.js"; +import createConsoleLogger from "../../helpers/consoleLogger/index.js"; +import { + compose, + debugEnabled, + orgMainConfigMain, +} from "../../helpers/constants/configParts/index.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; +import { CONSENT_OUT } from "../../helpers/constants/consent.js"; + +const networkLogger = createNetworkLogger(); + +createFixture({ + title: "C25148 - When default consent is 'in', consent can be revoked.", + requestHooks: [networkLogger.edgeEndpointLogs], +}); + +test.meta({ + ID: "C25148", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +const config = compose(orgMainConfigMain, debugEnabled); + +test("C25148 - When default consent is 'in', consent can be revoked", async () => { + const alloy = createAlloyProxy(); + await alloy.configure(config); + + // trigger an event + await alloy.sendEvent(); + + // revoke user consent + await alloy.setConsent(CONSENT_OUT); + + // trigger a second event + const logger = await createConsoleLogger(); + await alloy.sendEvent(); + await logger.warn.expectMessageMatching(/user declined consent/); + + // ensure only one event was sent + await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(1); + const stringifyRequest = JSON.parse( + networkLogger.edgeEndpointLogs.requests[0].request.body, + ); + await t.expect(stringifyRequest.events.length).eql(1); +}); diff --git a/packages/browser/test/functional/specs/Consent/C2593.js b/packages/browser/test/functional/specs/Consent/C2593.js new file mode 100644 index 000000000..8362c2412 --- /dev/null +++ b/packages/browser/test/functional/specs/Consent/C2593.js @@ -0,0 +1,52 @@ +/* +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 } from "testcafe"; +import createNetworkLogger from "../../helpers/networkLogger/index.js"; +import { responseStatus } from "../../helpers/assertions/index.js"; +import createFixture from "../../helpers/createFixture/index.js"; +import environmentContextConfig from "../../helpers/constants/environmentContextConfig.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; +import flushPromiseChains from "../../helpers/flushPromiseChains.js"; +import { CONSENT_IN } from "../../helpers/constants/consent.js"; + +const networkLogger = createNetworkLogger(); + +createFixture({ + title: "C2593: Event command sets consent to in.", + requestHooks: [networkLogger.edgeEndpointLogs], +}); + +test.meta({ + ID: "C2593", + SEVERITY: "P0", + TEST_RUN: "REGRESSION", +}); + +test("Test C2593: Event command consents to all purposes", async () => { + const alloy = createAlloyProxy(); + await alloy.configure({ + defaultConsent: "pending", + ...environmentContextConfig, + }); + // try to send an event and verify that it is queued + const sendEventResponse = await alloy.sendEventAsync(); + await flushPromiseChains(); + await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(0); + + // set the consent to in + await alloy.setConsent(CONSENT_IN); + + // ensure the event goes out + await sendEventResponse.result; + await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(1); + await responseStatus(networkLogger.edgeEndpointLogs.requests, [200, 207]); +}); diff --git a/packages/browser/test/functional/specs/Consent/C2594.js b/packages/browser/test/functional/specs/Consent/C2594.js new file mode 100644 index 000000000..244e5b4e1 --- /dev/null +++ b/packages/browser/test/functional/specs/Consent/C2594.js @@ -0,0 +1,53 @@ +/* +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 createFixture from "../../helpers/createFixture/index.js"; +import createNetworkLogger from "../../helpers/networkLogger/index.js"; +import { + compose, + orgMainConfigMain, + consentPending, + debugEnabled, +} from "../../helpers/constants/configParts/index.js"; +import createConsoleLogger from "../../helpers/consoleLogger/index.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; +import { CONSENT_OUT } from "../../helpers/constants/consent.js"; + +const config = compose(orgMainConfigMain, consentPending, debugEnabled); + +const networkLogger = createNetworkLogger(); + +createFixture({ + title: + "C2594: event command resolves promise with empty object if user consents to no purposes", + requestHooks: [networkLogger.edgeEndpointLogs], +}); + +test.meta({ + ID: "C2594", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +test("Test C2594: event command resolves promise with empty object if user consents to no purposes", async (t) => { + const alloy = createAlloyProxy(); + await alloy.configure(config); + const logger = await createConsoleLogger(); + + const sendEventResponse = await alloy.sendEventAsync(); + await alloy.setConsent(CONSENT_OUT); + + const result = await sendEventResponse.result; + await t.expect(result).eql({}); + await logger.warn.expectMessageMatching(/The user declined consent./); + // make sure no event requests were sent out + await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(0); +}); diff --git a/packages/browser/test/functional/specs/Consent/C2660.js b/packages/browser/test/functional/specs/Consent/C2660.js new file mode 100644 index 000000000..9eaf3032a --- /dev/null +++ b/packages/browser/test/functional/specs/Consent/C2660.js @@ -0,0 +1,70 @@ +/* +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 } from "testcafe"; +import createNetworkLogger from "../../helpers/networkLogger/index.js"; +import createFixture from "../../helpers/createFixture/index.js"; +import flushPromiseChains from "../../helpers/flushPromiseChains.js"; +import orgMainConfigMain from "../../helpers/constants/configParts/orgMainConfigMain.js"; +import { + compose, + consentPending, +} from "../../helpers/constants/configParts/index.js"; +import { TEST_PAGE as TEST_PAGE_URL } from "../../helpers/constants/url.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; +import { CONSENT_IN } from "../../helpers/constants/consent.js"; + +const networkLogger = createNetworkLogger(); + +createFixture({ + title: "C2660 - Context data is captured before user consents.", + requestHooks: [networkLogger.edgeEndpointLogs], +}); + +test.meta({ + ID: "C2660", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +const getContextUrlFromRequest = (request) => { + const parsedBody = JSON.parse(request.request.body); + return parsedBody.events[0].xdm.web.webPageDetails.URL; +}; + +test("C2660 - Context data is captured before user consents.", async () => { + const alloy = createAlloyProxy(); + await alloy.configure(compose(orgMainConfigMain, consentPending)); + + // send an event that will be queued + const sendEventResponse = await alloy.sendEventAsync(); + await flushPromiseChains(); + + // change something that will be collected by Context Component + await t.eval(() => { + window.location.hash = "foo"; + }); + + // set consent to flush the events queue + await alloy.setConsent(CONSENT_IN); + await sendEventResponse.result; + + // send another event to make sure the foo hash is collected normally + await alloy.sendEvent(); + + // expect that context was captured at the right time + await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(2); + const requests = networkLogger.edgeEndpointLogs.requests; + await t.expect(getContextUrlFromRequest(requests[0])).eql(TEST_PAGE_URL); + await t + .expect(getContextUrlFromRequest(requests[1])) + .eql(`${TEST_PAGE_URL}#foo`); +}); diff --git a/packages/browser/test/functional/specs/Consent/C28754.js b/packages/browser/test/functional/specs/Consent/C28754.js new file mode 100644 index 000000000..2d72fa229 --- /dev/null +++ b/packages/browser/test/functional/specs/Consent/C28754.js @@ -0,0 +1,68 @@ +/* +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 } from "testcafe"; +import createNetworkLogger from "../../helpers/networkLogger/index.js"; +import { responseStatus } from "../../helpers/assertions/index.js"; +import createFixture from "../../helpers/createFixture/index.js"; +import createResponse from "../../helpers/createResponse.js"; +import getResponseBody from "../../helpers/networkLogger/getResponseBody.js"; +import { + compose, + orgMainConfigMain, + consentPending, +} from "../../helpers/constants/configParts/index.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; + +import { CONSENT_OUT } from "../../helpers/constants/consent.js"; + +const config = compose(orgMainConfigMain, consentPending); + +const networkLogger = createNetworkLogger(); + +createFixture({ + title: + "C28754 - Consenting to no purposes should result in no data handles in the response.", + requestHooks: [networkLogger.setConsentEndpointLogs], +}); + +test.meta({ + ID: "C28754", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +test("C28754 - Consenting to no purposes should result in no data handles in the response.", async () => { + const alloy = createAlloyProxy(); + await alloy.configure(config); + + await alloy.setConsent(CONSENT_OUT); + await responseStatus( + networkLogger.setConsentEndpointLogs.requests, + [200, 207], + ); + + const response = JSON.parse( + getResponseBody(networkLogger.setConsentEndpointLogs.requests[0]), + ); + + const alloyResponse = createResponse({ content: response }); + + const idSyncsPayload = alloyResponse.getPayloadsByType("identity:exchange"); + const personalizationPayload = alloyResponse.getPayloadsByType( + "personalization:decisions", + ); + const audiencesPayload = alloyResponse.getPayloadsByType("activation:push"); + + await t.expect(idSyncsPayload).eql([]); + await t.expect(personalizationPayload).eql([]); + await t.expect(audiencesPayload).eql([]); +}); diff --git a/packages/browser/test/functional/specs/Consent/C5594870.js b/packages/browser/test/functional/specs/Consent/C5594870.js new file mode 100644 index 000000000..4c47d7196 --- /dev/null +++ b/packages/browser/test/functional/specs/Consent/C5594870.js @@ -0,0 +1,61 @@ +/* +Copyright 2022 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 } from "testcafe"; +import createFixture from "../../helpers/createFixture/index.js"; +import { + compose, + orgMainConfigMain, + debugEnabled, +} from "../../helpers/constants/configParts/index.js"; +import createNetworkLogger from "../../helpers/networkLogger/index.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; +import createRandomEcid from "../../helpers/createRandomEcid.js"; +import { TEST_PAGE as TEST_PAGE_URL } from "../../helpers/constants/url.js"; +import { CONSENT_IN } from "../../helpers/constants/consent.js"; +import getReturnedEcid from "../../helpers/networkLogger/getReturnedEcid.js"; +import createAdobeMC from "../../helpers/createAdobeMC.js"; + +const config = compose( + orgMainConfigMain, + { defaultConsent: "pending" }, + debugEnabled, +); + +const networkLogger = createNetworkLogger(); + +const id = createRandomEcid(); +const adobemc = createAdobeMC({ id }); + +createFixture({ + url: `${TEST_PAGE_URL}?adobe_mc=${adobemc}`, + title: + "C5594870: Identity can be set via the adobe_mc query string parameter when calling set-consent", + requestHooks: [networkLogger.setConsentEndpointLogs], +}); + +test.meta({ + ID: "C5594870", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +test("C5594870: Identity can be set via the adobe_mc query string parameter when calling set-consent", async () => { + const alloy = createAlloyProxy(); + await alloy.configure(config); + + await alloy.setConsent(CONSENT_IN); + const ecid = getReturnedEcid( + networkLogger.setConsentEndpointLogs.requests[0], + ); + await t.expect(ecid).eql(id); +}); diff --git a/packages/browser/test/functional/specs/Consent/IAB/C224670.js b/packages/browser/test/functional/specs/Consent/IAB/C224670.js new file mode 100644 index 000000000..aa1c47999 --- /dev/null +++ b/packages/browser/test/functional/specs/Consent/IAB/C224670.js @@ -0,0 +1,74 @@ +/* +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 } from "testcafe"; +import createNetworkLogger from "../../../helpers/networkLogger/index.js"; +import { responseStatus } from "../../../helpers/assertions/index.js"; +import createFixture from "../../../helpers/createFixture/index.js"; +import createResponse from "../../../helpers/createResponse.js"; +import getResponseBody from "../../../helpers/networkLogger/getResponseBody.js"; +import cookies from "../../../helpers/cookies.js"; +import { + compose, + orgMainConfigMain, + consentPending, + debugEnabled, +} from "../../../helpers/constants/configParts/index.js"; +import { MAIN_CONSENT_COOKIE_NAME } from "../../../helpers/constants/cookies.js"; +import createAlloyProxy from "../../../helpers/createAlloyProxy.js"; +import { IAB_CONSENT_IN } from "../../../helpers/constants/consent.js"; + +const config = compose(orgMainConfigMain, consentPending, debugEnabled); + +const networkLogger = createNetworkLogger(); + +createFixture({ + title: "C224670: Opt in to IAB using the setConsent command.", + requestHooks: [ + networkLogger.setConsentEndpointLogs, + networkLogger.edgeEndpointLogs, + ], +}); + +test.meta({ + ID: "C224670", + SEVERITY: "P0", + TEST_RUN: "REGRESSION", +}); + +test("Test C224670: Opt in to IAB", async () => { + const alloy = createAlloyProxy(); + await alloy.configure(config); + await alloy.setConsent(IAB_CONSENT_IN); + + await t.expect(networkLogger.setConsentEndpointLogs.requests.length).eql(1); + await responseStatus(networkLogger.edgeEndpointLogs.requests, [200, 207]); + + const consentRawResponse = JSON.parse( + getResponseBody(networkLogger.setConsentEndpointLogs.requests[0]), + ); + + const consentResponse = createResponse({ content: consentRawResponse }); + + // 1. The set-consent response should contain the Consent cookie: { general: in } + const consentCookieValue = await cookies.get(MAIN_CONSENT_COOKIE_NAME); + + await t.expect(consentCookieValue).ok("No consent cookie found."); + await t.expect(consentCookieValue).eql("general=in"); + + // 2. The ECID should exist in the response payload as well, if queried + const identityHandle = consentResponse.getPayloadsByType("identity:result"); + const returnedNamespaces = identityHandle.map((i) => i.namespace.code); + await t.expect(returnedNamespaces).contains("ECID"); + + await alloy.sendEvent(); + await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(1); +}); diff --git a/packages/browser/test/functional/specs/Consent/IAB/C224671.js b/packages/browser/test/functional/specs/Consent/IAB/C224671.js new file mode 100644 index 000000000..e62ddea57 --- /dev/null +++ b/packages/browser/test/functional/specs/Consent/IAB/C224671.js @@ -0,0 +1,79 @@ +/* +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 } from "testcafe"; +import createNetworkLogger from "../../../helpers/networkLogger/index.js"; +import { responseStatus } from "../../../helpers/assertions/index.js"; +import createFixture from "../../../helpers/createFixture/index.js"; +import createResponse from "../../../helpers/createResponse.js"; +import getResponseBody from "../../../helpers/networkLogger/getResponseBody.js"; +import cookies from "../../../helpers/cookies.js"; +import { + compose, + orgMainConfigMain, + consentPending, + debugEnabled, +} from "../../../helpers/constants/configParts/index.js"; +import { MAIN_CONSENT_COOKIE_NAME } from "../../../helpers/constants/cookies.js"; +import createAlloyProxy from "../../../helpers/createAlloyProxy.js"; +import { + IAB_NO_PURPOSE_ONE, + IAB_NO_ADOBE_VENDOR, +} from "../../../helpers/constants/consent.js"; + +const config = compose(orgMainConfigMain, consentPending, debugEnabled); + +const networkLogger = createNetworkLogger(); + +createFixture({ + title: "C224671: Opt out of IAB using the setConsent command.", + requestHooks: [ + networkLogger.setConsentEndpointLogs, + networkLogger.edgeEndpointLogs, + ], +}); + +test.meta({ + ID: "C224671", + SEVERITY: "P0", + TEST_RUN: "REGRESSION", +}); + +[IAB_NO_PURPOSE_ONE, IAB_NO_ADOBE_VENDOR].forEach((consent) => { + test("Test C224671: Opt out of IAB - No Purpose 1 & No Vendor", async () => { + const alloy = createAlloyProxy(); + await alloy.configure(config); + await alloy.setConsent(consent); + + await t.expect(networkLogger.setConsentEndpointLogs.requests.length).eql(1); + await responseStatus(networkLogger.edgeEndpointLogs.requests, [200, 207]); + + const consentRawResponse = JSON.parse( + getResponseBody(networkLogger.setConsentEndpointLogs.requests[0]), + ); + + const consentResponse = createResponse({ content: consentRawResponse }); + + // 1. The set-consent response should contain the Consent cookie: { general: out } + const consentCookieValue = await cookies.get(MAIN_CONSENT_COOKIE_NAME); + + await t.expect(consentCookieValue).ok("No consent cookie found."); + await t.expect(consentCookieValue).eql("general=out"); + + // 2. The ECID should exist in the response payload as well, if queried + const identityHandle = consentResponse.getPayloadsByType("identity:result"); + const returnedNamespaces = identityHandle.map((i) => i.namespace.code); + await t.expect(returnedNamespaces).contains("ECID"); + + await alloy.sendEvent(); + await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(0); + }); +}); diff --git a/packages/browser/test/functional/specs/Consent/IAB/C224672.js b/packages/browser/test/functional/specs/Consent/IAB/C224672.js new file mode 100644 index 000000000..690ab5976 --- /dev/null +++ b/packages/browser/test/functional/specs/Consent/IAB/C224672.js @@ -0,0 +1,75 @@ +/* +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 } from "testcafe"; +import createNetworkLogger from "../../../helpers/networkLogger/index.js"; +import { responseStatus } from "../../../helpers/assertions/index.js"; +import createFixture from "../../../helpers/createFixture/index.js"; +import createResponse from "../../../helpers/createResponse.js"; +import getResponseBody from "../../../helpers/networkLogger/getResponseBody.js"; +import cookies from "../../../helpers/cookies.js"; +import { + compose, + orgMainConfigMain, + consentPending, + debugEnabled, +} from "../../../helpers/constants/configParts/index.js"; +import { MAIN_CONSENT_COOKIE_NAME } from "../../../helpers/constants/cookies.js"; +import createAlloyProxy from "../../../helpers/createAlloyProxy.js"; +import { IAB_CONSENT_IN_PERSONAL_DATA } from "../../../helpers/constants/consent.js"; + +const config = compose(orgMainConfigMain, consentPending, debugEnabled); + +const networkLogger = createNetworkLogger(); + +createFixture({ + title: + "C224672: Passing the `gdprContainsPersonalData` flag should return in the response.", + requestHooks: [ + networkLogger.setConsentEndpointLogs, + networkLogger.edgeEndpointLogs, + ], +}); + +test.meta({ + ID: "C224672", + SEVERITY: "P0", + TEST_RUN: "REGRESSION", +}); + +test("Test C224672: Passing the `gdprContainsPersonalData` flag should return in the response", async () => { + const alloy = createAlloyProxy(); + await alloy.configure(config); + await alloy.setConsent(IAB_CONSENT_IN_PERSONAL_DATA); + + await t.expect(networkLogger.setConsentEndpointLogs.requests.length).eql(1); + await responseStatus(networkLogger.edgeEndpointLogs.requests, [200, 207]); + + const consentRawResponse = JSON.parse( + getResponseBody(networkLogger.setConsentEndpointLogs.requests[0]), + ); + + const consentResponse = createResponse({ content: consentRawResponse }); + + // 1. The set-consent response should contain the Consent cookie: { general: in } + const consentCookieValue = await cookies.get(MAIN_CONSENT_COOKIE_NAME); + + await t.expect(consentCookieValue).ok("No consent cookie found."); + await t.expect(consentCookieValue).eql("general=in"); + + // 2. The ECID should exist in the response payload as well, if queried + const identityHandle = consentResponse.getPayloadsByType("identity:result"); + const returnedNamespaces = identityHandle.map((i) => i.namespace.code); + await t.expect(returnedNamespaces).contains("ECID"); + + await alloy.sendEvent(); + await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(1); +}); diff --git a/packages/browser/test/functional/specs/Consent/IAB/C224673.js b/packages/browser/test/functional/specs/Consent/IAB/C224673.js new file mode 100644 index 000000000..6e832349f --- /dev/null +++ b/packages/browser/test/functional/specs/Consent/IAB/C224673.js @@ -0,0 +1,74 @@ +/* +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 } from "testcafe"; +import createNetworkLogger from "../../../helpers/networkLogger/index.js"; +import { responseStatus } from "../../../helpers/assertions/index.js"; +import createFixture from "../../../helpers/createFixture/index.js"; +import createResponse from "../../../helpers/createResponse.js"; +import getResponseBody from "../../../helpers/networkLogger/getResponseBody.js"; +import cookies from "../../../helpers/cookies.js"; +import { + compose, + orgMainConfigMain, + consentPending, + debugEnabled, +} from "../../../helpers/constants/configParts/index.js"; +import { MAIN_CONSENT_COOKIE_NAME } from "../../../helpers/constants/cookies.js"; +import createAlloyProxy from "../../../helpers/createAlloyProxy.js"; +import { IAB_CONSENT_IN_NO_GDPR } from "../../../helpers/constants/consent.js"; + +const config = compose(orgMainConfigMain, consentPending, debugEnabled); + +const networkLogger = createNetworkLogger(); + +createFixture({ + title: "C224673: Opt in to IAB while gdprApplies is FALSE.", + requestHooks: [ + networkLogger.setConsentEndpointLogs, + networkLogger.edgeEndpointLogs, + ], +}); + +test.meta({ + ID: "C224673", + SEVERITY: "P0", + TEST_RUN: "REGRESSION", +}); + +test("Test C224673: Opt in to IAB while gdprApplies is FALSE", async () => { + const alloy = createAlloyProxy(); + await alloy.configure(config); + await alloy.setConsent(IAB_CONSENT_IN_NO_GDPR); + + await t.expect(networkLogger.setConsentEndpointLogs.requests.length).eql(1); + await responseStatus(networkLogger.edgeEndpointLogs.requests, [200, 207]); + + const consentRawResponse = JSON.parse( + getResponseBody(networkLogger.setConsentEndpointLogs.requests[0]), + ); + + const consentResponse = createResponse({ content: consentRawResponse }); + + // 1. The set-consent response should contain the Consent cookie: { general: in } + const consentCookieValue = await cookies.get(MAIN_CONSENT_COOKIE_NAME); + + await t.expect(consentCookieValue).ok("No consent cookie found."); + await t.expect(consentCookieValue).eql("general=in"); + + // 2. The ECID should exist in the response payload as well, if queried + const identityHandle = consentResponse.getPayloadsByType("identity:result"); + const returnedNamespaces = identityHandle.map((i) => i.namespace.code); + await t.expect(returnedNamespaces).contains("ECID"); + + await alloy.sendEvent(); + await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(1); +}); diff --git a/packages/browser/test/functional/specs/Consent/IAB/C224674.js b/packages/browser/test/functional/specs/Consent/IAB/C224674.js new file mode 100644 index 000000000..61a5bde00 --- /dev/null +++ b/packages/browser/test/functional/specs/Consent/IAB/C224674.js @@ -0,0 +1,74 @@ +/* +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 } from "testcafe"; +import createNetworkLogger from "../../../helpers/networkLogger/index.js"; +import { responseStatus } from "../../../helpers/assertions/index.js"; +import createFixture from "../../../helpers/createFixture/index.js"; +import createResponse from "../../../helpers/createResponse.js"; +import getResponseBody from "../../../helpers/networkLogger/getResponseBody.js"; +import cookies from "../../../helpers/cookies.js"; +import { + compose, + orgMainConfigMain, + consentPending, + debugEnabled, +} from "../../../helpers/constants/configParts/index.js"; +import { MAIN_CONSENT_COOKIE_NAME } from "../../../helpers/constants/cookies.js"; +import createAlloyProxy from "../../../helpers/createAlloyProxy.js"; +import { IAB_NO_PURPOSE_ONE_NO_GRPR } from "../../../helpers/constants/consent.js"; + +const config = compose(orgMainConfigMain, consentPending, debugEnabled); + +const networkLogger = createNetworkLogger(); + +createFixture({ + title: "C224674: Opt out to IAB while gdprApplies is FALSE.", + requestHooks: [ + networkLogger.setConsentEndpointLogs, + networkLogger.edgeEndpointLogs, + ], +}); + +test.meta({ + ID: "C224674", + SEVERITY: "P0", + TEST_RUN: "REGRESSION", +}); + +test("Test C224674: Opt out to IAB while gdprApplies is FALSE", async () => { + const alloy = createAlloyProxy(); + await alloy.configure(config); + await alloy.setConsent(IAB_NO_PURPOSE_ONE_NO_GRPR); + + await t.expect(networkLogger.setConsentEndpointLogs.requests.length).eql(1); + await responseStatus(networkLogger.edgeEndpointLogs.requests, [200, 207]); + + const consentRawResponse = JSON.parse( + getResponseBody(networkLogger.setConsentEndpointLogs.requests[0]), + ); + + const consentResponse = createResponse({ content: consentRawResponse }); + + // 1. The set-consent response should contain the Consent cookie: { general: in } + const consentCookieValue = await cookies.get(MAIN_CONSENT_COOKIE_NAME); + + await t.expect(consentCookieValue).ok("No consent cookie found."); + await t.expect(consentCookieValue).eql("general=in"); + + // 2. The ECID should exist in the response payload as well, if queried + const identityHandle = consentResponse.getPayloadsByType("identity:result"); + const returnedNamespaces = identityHandle.map((i) => i.namespace.code); + await t.expect(returnedNamespaces).contains("ECID"); + + await alloy.sendEvent(); + await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(1); +}); diff --git a/packages/browser/test/functional/specs/Consent/IAB/C224675.js b/packages/browser/test/functional/specs/Consent/IAB/C224675.js new file mode 100644 index 000000000..67aa4924e --- /dev/null +++ b/packages/browser/test/functional/specs/Consent/IAB/C224675.js @@ -0,0 +1,124 @@ +/* +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 } from "testcafe"; +import createNetworkLogger from "../../../helpers/networkLogger/index.js"; +import createFixture from "../../../helpers/createFixture/index.js"; +import { + compose, + orgMainConfigMain, + consentPending, + debugEnabled, +} from "../../../helpers/constants/configParts/index.js"; +import createAlloyProxy from "../../../helpers/createAlloyProxy.js"; + +const config = compose(orgMainConfigMain, consentPending, debugEnabled); + +const networkLogger = createNetworkLogger(); + +createFixture({ + title: + "C224675: Passing invalid consent options should throw a validation error.", + requestHooks: [ + networkLogger.setConsentEndpointLogs, + networkLogger.edgeEndpointLogs, + ], +}); + +test.meta({ + ID: "C224675", + SEVERITY: "P0", + TEST_RUN: "REGRESSION", +}); + +test("Test C224675: Passing invalid consent options should throw a validation error", async () => { + const alloy = createAlloyProxy(); + await alloy.configure(config); + + const errorMessageForInvalidStandard = await alloy.setConsentErrorMessage({ + consent: [ + { + standard: "IAB", + version: "2.0", + value: "CO052l-O052l-DGAMBFRACBgAIBAAAAAAIYgEawAQEagAAAA", + }, + ], + }); + + await t + .expect(errorMessageForInvalidStandard) + .ok("Expected the setConsent command to be rejected"); + + await t + .expect(errorMessageForInvalidStandard) + .contains("The server responded with a status code 400") + .expect(errorMessageForInvalidStandard) + .contains("EXEG-0102-400"); + + const errorMessageForInvalidVersion = await alloy.setConsentErrorMessage({ + consent: [ + { + standard: "IAB TCF", + version: "6.9", + value: "CO052l-O052l-DGAMBFRACBgAIBAAAAAAIYgEawAQEagAAAA", + }, + ], + }); + + await t + .expect(errorMessageForInvalidVersion) + .ok("Expected the setConsent command to be rejected"); + + await t + .expect(errorMessageForInvalidVersion) + .contains("The server responded with a status code 400") + .expect(errorMessageForInvalidVersion) + .contains("EXEG-0102-400"); + + const errorMessageForInvalidValue = await alloy.setConsentErrorMessage({ + consent: [ + { + standard: "IAB TCF", + version: "2.0", + }, + ], + }); + + await t + .expect(errorMessageForInvalidValue) + .ok("Expected the setConsent command to be rejected"); + + await t + .expect(errorMessageForInvalidValue) + .contains("The server responded with a status code 400") + .expect(errorMessageForInvalidValue) + .contains("EXEG-0103-400"); + + const errorMessageForEmptyValue = await alloy.setConsentErrorMessage({ + consent: [ + { + standard: "IAB TCF", + version: "2.0", + value: "", + }, + ], + }); + + await t + .expect(errorMessageForEmptyValue) + .ok("Expected the setConsent command to be rejected"); + + await t + .expect(errorMessageForEmptyValue) + .contains("The server responded with a status code 422") + .expect(errorMessageForEmptyValue) + .contains("EXEG-0104-422"); +}); diff --git a/packages/browser/test/functional/specs/Consent/IAB/C224676.js b/packages/browser/test/functional/specs/Consent/IAB/C224676.js new file mode 100644 index 000000000..b3681d5fe --- /dev/null +++ b/packages/browser/test/functional/specs/Consent/IAB/C224676.js @@ -0,0 +1,83 @@ +/* +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 } from "testcafe"; +import createNetworkLogger from "../../../helpers/networkLogger/index.js"; +import { responseStatus } from "../../../helpers/assertions/index.js"; +import createFixture from "../../../helpers/createFixture/index.js"; +import createResponse from "../../../helpers/createResponse.js"; +import getResponseBody from "../../../helpers/networkLogger/getResponseBody.js"; +import cookies from "../../../helpers/cookies.js"; +import { + compose, + orgMainConfigMain, + debugEnabled, +} from "../../../helpers/constants/configParts/index.js"; +import { MAIN_CONSENT_COOKIE_NAME } from "../../../helpers/constants/cookies.js"; +import createAlloyProxy from "../../../helpers/createAlloyProxy.js"; + +const config = compose(orgMainConfigMain, debugEnabled); + +const networkLogger = createNetworkLogger(); + +createFixture({ + title: "C224676: Passing a positive Consent in the sendEvent command.", + requestHooks: [networkLogger.edgeEndpointLogs], +}); + +test.meta({ + ID: "C224676", + SEVERITY: "P0", + TEST_RUN: "REGRESSION", +}); + +const eventOptionsWithConsent = { + xdm: { + consentStrings: [ + { + consentStandard: "IAB TCF", + consentStandardVersion: "2.0", + consentStringValue: "CO052l-O052l-DGAMBFRACBgAIBAAAAAAIYgEawAQEagAAAA", + gdprApplies: true, + containsPersonalData: false, + }, + ], + }, +}; + +test("Test C224676: Passing a positive Consent in the sendEvent command", async () => { + const alloy = createAlloyProxy(); + await alloy.configure(config); + await alloy.sendEvent(eventOptionsWithConsent); + + await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(1); + await responseStatus(networkLogger.edgeEndpointLogs.requests, [200, 207]); + + const rawResponse = JSON.parse( + getResponseBody(networkLogger.edgeEndpointLogs.requests[0]), + ); + + const response = createResponse({ content: rawResponse }); + + // 1. The set-consent response should contain the Consent cookie: { general: in } + const consentCookieValue = await cookies.get(MAIN_CONSENT_COOKIE_NAME); + + await t.expect(consentCookieValue).ok("No consent cookie found."); + await t.expect(consentCookieValue).eql("general=in"); + + // 2. The ECID should exist in the response payload as well, if queried + const identityHandle = response.getPayloadsByType("identity:result"); + const returnedNamespaces = identityHandle.map((i) => i.namespace.code); + await t.expect(returnedNamespaces).contains("ECID"); + + await alloy.sendEvent(); + await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(2); +}); diff --git a/packages/browser/test/functional/specs/Consent/IAB/C224677.js b/packages/browser/test/functional/specs/Consent/IAB/C224677.js new file mode 100644 index 000000000..735d464e6 --- /dev/null +++ b/packages/browser/test/functional/specs/Consent/IAB/C224677.js @@ -0,0 +1,91 @@ +/* +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 } from "testcafe"; +import createNetworkLogger from "../../../helpers/networkLogger/index.js"; +import createFixture from "../../../helpers/createFixture/index.js"; +import createResponse from "../../../helpers/createResponse.js"; +import getResponseBody from "../../../helpers/networkLogger/getResponseBody.js"; +import cookies from "../../../helpers/cookies.js"; +import { + compose, + orgMainConfigMain, + debugEnabled, +} from "../../../helpers/constants/configParts/index.js"; +import { MAIN_CONSENT_COOKIE_NAME } from "../../../helpers/constants/cookies.js"; +import createAlloyProxy from "../../../helpers/createAlloyProxy.js"; +import { IAB_NO_PURPOSE_TEN } from "../../../helpers/constants/consent.js"; + +const config = compose(orgMainConfigMain, debugEnabled); + +const networkLogger = createNetworkLogger(); + +createFixture({ + title: "C224677: Call setConsent when purpose 10 is FALSE.", + requestHooks: [ + networkLogger.setConsentEndpointLogs, + networkLogger.edgeEndpointLogs, + ], +}); + +test.meta({ + ID: "C224677", + SEVERITY: "P0", + TEST_RUN: "REGRESSION", +}); + +test("Test C224677: Call setConsent when purpose 10 is FALSE", async () => { + const alloy = createAlloyProxy(); + await alloy.configure(config); + await alloy.setConsent(IAB_NO_PURPOSE_TEN); + + await t.expect(networkLogger.setConsentEndpointLogs.requests.length).eql(1); + + const rawResponse = JSON.parse( + getResponseBody(networkLogger.setConsentEndpointLogs.requests[0]), + ); + + const response = createResponse({ content: rawResponse }); + + // 1. The set-consent response should contain the Consent cookie: { general: in } + const consentCookieValue = await cookies.get(MAIN_CONSENT_COOKIE_NAME); + + await t.expect(consentCookieValue).ok("No consent cookie found."); + await t.expect(consentCookieValue).eql("general=in"); + + // 2. The ECID should exist in the response payload as well, if queried + const identityHandle = response.getPayloadsByType("identity:result"); + const returnedNamespaces = identityHandle.map((i) => i.namespace.code); + await t.expect(returnedNamespaces).contains("ECID"); + + // 3. Event calls going forward should remain opted in, even though AAM opts out consents with no purpose 10. + await alloy.sendEvent(); + const rawEventResponse = JSON.parse( + getResponseBody(networkLogger.edgeEndpointLogs.requests[0]), + ); + const eventResponse = createResponse({ content: rawEventResponse }); + + // 4. No warning message regarding opt-out should be returned anymore + const warningTypes = eventResponse.getWarnings().map((w) => w.type); + await t + .expect(warningTypes) + .notContains("https://ns.adobe.com/aep/errors/EXEG-0301-200"); + + await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(1); + await t + .expect( + networkLogger.edgeEndpointLogs.count( + ({ response: { statusCode } }) => + statusCode === 200 || statusCode === 207, + ), + ) + .eql(1); +}); diff --git a/packages/browser/test/functional/specs/Consent/IAB/C224678.js b/packages/browser/test/functional/specs/Consent/IAB/C224678.js new file mode 100644 index 000000000..0ae00d37d --- /dev/null +++ b/packages/browser/test/functional/specs/Consent/IAB/C224678.js @@ -0,0 +1,111 @@ +/* +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 } from "testcafe"; +import createNetworkLogger from "../../../helpers/networkLogger/index.js"; +import { responseStatus } from "../../../helpers/assertions/index.js"; +import createFixture from "../../../helpers/createFixture/index.js"; +import createResponse from "../../../helpers/createResponse.js"; +import getResponseBody from "../../../helpers/networkLogger/getResponseBody.js"; +import cookies from "../../../helpers/cookies.js"; +import { + compose, + orgMainConfigMain, + debugEnabled, +} from "../../../helpers/constants/configParts/index.js"; +import { MAIN_CONSENT_COOKIE_NAME } from "../../../helpers/constants/cookies.js"; +import createAlloyProxy from "../../../helpers/createAlloyProxy.js"; + +const config = compose(orgMainConfigMain, debugEnabled); + +const networkLogger = createNetworkLogger(); + +createFixture({ + title: "C224678: Passing a negative Consent in the sendEvent command.", + requestHooks: [networkLogger.edgeEndpointLogs], +}); + +test.meta({ + ID: "C224678", + SEVERITY: "P0", + TEST_RUN: "REGRESSION", +}); + +// Consent with no Purpose 1, should result in Opt-Out. +const sendEventOptions = { + xdm: { + consentStrings: [ + { + consentStandard: "IAB TCF", + consentStandardVersion: "2.0", + consentStringValue: "CO052oTO052oTDGAMBFRACBgAABAAAAAAIYgEawAQEagAAAA", + gdprApplies: true, + containsPersonalData: false, + }, + ], + }, +}; + +test("Test C224678: Passing a negative Consent in the sendEvent command", async () => { + const alloy = createAlloyProxy(); + await alloy.configure(config); + const errorMessage = await alloy.sendEventErrorMessage(sendEventOptions); + + await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(1); + await responseStatus(networkLogger.edgeEndpointLogs.requests, [200, 207]); + + const rawResponse = JSON.parse( + getResponseBody(networkLogger.edgeEndpointLogs.requests[0]), + ); + + const response = createResponse({ content: rawResponse }); + + // 1. The set-consent response should contain the Consent cookie: { general: out } + const consentCookieValue = await cookies.get(MAIN_CONSENT_COOKIE_NAME); + + await t.expect(consentCookieValue).ok("No consent cookie found."); + await t.expect(consentCookieValue).eql("general=out"); + + // 2. The ECID should exist in the response payload as well, even if queried + const identityHandle = response.getPayloadsByType("identity:result"); + const returnedNamespaces = identityHandle.map((i) => i.namespace.code); + await t.expect(returnedNamespaces).contains("ECID"); + + // 3. Should not have any activation, ID Syncs or decisions in the response. + const handlesThatShouldBeMissing = [ + "activation:push", + "identity:exchange", + "personalization:decisions", + ].reduce((handles, handleType) => { + const handle = response.getPayloadsByType(handleType); + if (handle.length) { + handles.push(handle); + } + return handles; + }, []); + + await t.expect(handlesThatShouldBeMissing.length).eql(0); + + // 4. The server doesn't throw error messages when there is no consent + await t + .expect(errorMessage) + .notOk("Event returned an error when we expected it not to."); + + // 5. But returns a warning message confirming the opt-out + const warningTypes = response.getWarnings().map((w) => w.type); + await t + .expect(warningTypes) + .contains("https://ns.adobe.com/aep/errors/EXEG-0301-200"); + + // 6. Events should be blocked going forward because we are opted out. + await alloy.sendEvent(); + await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(1); +}); diff --git a/packages/browser/test/functional/specs/Context/C1911390.js b/packages/browser/test/functional/specs/Context/C1911390.js new file mode 100644 index 000000000..4f2f3bd2a --- /dev/null +++ b/packages/browser/test/functional/specs/Context/C1911390.js @@ -0,0 +1,104 @@ +/* +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 } from "testcafe"; +import createNetworkLogger from "../../helpers/networkLogger/index.js"; +import createFixture from "../../helpers/createFixture/index.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; +import { orgMainConfigMain } from "../../helpers/constants/configParts/index.js"; + +const networkLogger = createNetworkLogger(); + +const ID = "C1911390"; +const DESCRIPTION = `${ID} - Ensure user-provided fields for context data don't leak across requests.`; + +createFixture({ + title: DESCRIPTION, + requestHooks: [networkLogger.edgeEndpointLogs], +}); + +test.meta({ + ID, + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +test(DESCRIPTION, async () => { + const alloy = createAlloyProxy(); + await alloy.configure(orgMainConfigMain); + await alloy.sendEvent({ + xdm: { + device: { + customDeviceField: "foo", + }, + environment: { + customEnvironmentField: "foo", + }, + implementationDetails: { + customImplementationDetailsField: "foo", + }, + placeContext: { + customPlaceContextField: "foo", + }, + web: { + customWebField: "foo", + }, + }, + }); + + await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(1); + + let parsedBody = JSON.parse( + networkLogger.edgeEndpointLogs.requests[0].request.body, + ); + let sentXdm = parsedBody.events[0].xdm; + + await t + .expect(sentXdm.device.customDeviceField) + .eql("foo", "custom device field incorrectly populated"); + await t + .expect(sentXdm.environment.customEnvironmentField) + .eql("foo", "custom environment field incorrectly populated"); + await t + .expect(sentXdm.implementationDetails.customImplementationDetailsField) + .eql("foo", "custom implementation details field incorrectly populated"); + await t + .expect(sentXdm.placeContext.customPlaceContextField) + .eql("foo", "custom place context field incorrectly populated"); + await t + .expect(sentXdm.web.customWebField) + .eql("foo", "custom web field incorrectly populated"); + + await alloy.sendEvent({}); + + await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(2); + + parsedBody = JSON.parse( + networkLogger.edgeEndpointLogs.requests[1].request.body, + ); + sentXdm = parsedBody.events[0].xdm; + + await t + .expect(sentXdm.device.customDeviceField) + .notOk("custom device field should be undefined"); + await t + .expect(sentXdm.environment.customEnvironmentField) + .notOk("custom environment field should be undefined"); + await t + .expect(sentXdm.implementationDetails.customImplementationDetailsField) + .notOk("custom implementation details field should be undefined"); + await t + .expect(sentXdm.placeContext.customPlaceContextField) + .notOk("custom place context field should be undefined"); + await t + .expect(sentXdm.web.customWebField) + .notOk("custom web field should be undefined"); +}); diff --git a/packages/browser/test/functional/specs/Context/C2597.js b/packages/browser/test/functional/specs/Context/C2597.js new file mode 100644 index 000000000..f950c6bb4 --- /dev/null +++ b/packages/browser/test/functional/specs/Context/C2597.js @@ -0,0 +1,60 @@ +/* +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 } from "testcafe"; +import createNetworkLogger from "../../helpers/networkLogger/index.js"; +import { responseStatus } from "../../helpers/assertions/index.js"; +import createFixture from "../../helpers/createFixture/index.js"; +import { orgMainConfigMain } from "../../helpers/constants/configParts/index.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; +import isUserAgentClientHintsSupported from "../../helpers/isUserAgentClientHintsSupported.js"; + +const networkLogger = createNetworkLogger(); + +const ID = "C2597"; +const DESCRIPTION = `${ID} - Adds all context data to requests by default.`; + +createFixture({ + title: DESCRIPTION, + requestHooks: [networkLogger.edgeEndpointLogs], +}); + +test.meta({ + ID, + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +test(DESCRIPTION, async () => { + const alloy = createAlloyProxy(); + await alloy.configure(orgMainConfigMain); + await alloy.sendEvent(); + + await responseStatus(networkLogger.edgeEndpointLogs.requests, [200, 207]); + await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(1); + + const parsedBody = JSON.parse( + networkLogger.edgeEndpointLogs.requests[0].request.body, + ); + + await t.expect(parsedBody.events[0].xdm.device).ok(); + await t.expect(parsedBody.events[0].xdm.placeContext).ok(); + await t.expect(parsedBody.events[0].xdm.environment.type).ok(); + await t.expect(parsedBody.events[0].xdm.web.webPageDetails).ok(); + if (await isUserAgentClientHintsSupported()) { + await t + .expect( + parsedBody.events[0].xdm?.environment?.browserDetails + ?.userAgentClientHints, + ) + .notOk(); + } +}); diff --git a/packages/browser/test/functional/specs/Context/C2598.js b/packages/browser/test/functional/specs/Context/C2598.js new file mode 100644 index 000000000..6b53c5f29 --- /dev/null +++ b/packages/browser/test/functional/specs/Context/C2598.js @@ -0,0 +1,77 @@ +/* +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 } from "testcafe"; +import createNetworkLogger from "../../helpers/networkLogger/index.js"; +import { responseStatus } from "../../helpers/assertions/index.js"; +import createFixture from "../../helpers/createFixture/index.js"; +import webContextConfig from "../../helpers/constants/webContextConfig.js"; +import { TEST_PAGE as TEST_PAGE_URL } from "../../helpers/constants/url.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; +import isUserAgentClientHintsSupported from "../../helpers/isUserAgentClientHintsSupported.js"; + +const networkLogger = createNetworkLogger(); + +const ID = "C2598"; +const DESCRIPTION = `${ID} - Adds only web context data when only web is specified in configuration.`; + +createFixture({ + title: DESCRIPTION, + requestHooks: [networkLogger.edgeEndpointLogs], + url: TEST_PAGE_URL, +}); + +test.meta({ + ID, + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +test(DESCRIPTION, async () => { + // navigate to set the document.referrer + await t.eval(() => { + window.document.location = `${window.document.location}`; + }); + + const alloy = createAlloyProxy(); + await alloy.configure(webContextConfig); + await alloy.sendEvent(); + + await responseStatus(networkLogger.edgeEndpointLogs.requests, [200, 207]); + await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(1); + + const parsedBody = JSON.parse( + networkLogger.edgeEndpointLogs.requests[0].request.body, + ); + + await t.expect(parsedBody.events[0].xdm.web).ok(); + await t.expect(parsedBody.events[0].xdm.web.webPageDetails).ok(); + await t + .expect(parsedBody.events[0].xdm.web.webPageDetails.URL) + .eql(TEST_PAGE_URL); + await t.expect(parsedBody.events[0].xdm.web.webReferrer).ok(); + await t + .expect(parsedBody.events[0].xdm.web.webReferrer.URL) + .eql(TEST_PAGE_URL); + + await t.expect(parsedBody.events[0].xdm.device).notOk(); + await t.expect(parsedBody.events[0].xdm.placeContext).notOk(); + await t.expect(parsedBody.events[0].xdm.environment).notOk(); + + if (await isUserAgentClientHintsSupported()) { + await t + .expect( + parsedBody.events[0].xdm?.environment?.browserDetails + ?.userAgentClientHints, + ) + .notOk(); + } +}); diff --git a/packages/browser/test/functional/specs/Context/C2599.js b/packages/browser/test/functional/specs/Context/C2599.js new file mode 100644 index 000000000..5e1c1c43d --- /dev/null +++ b/packages/browser/test/functional/specs/Context/C2599.js @@ -0,0 +1,71 @@ +/* +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 } from "testcafe"; +import createNetworkLogger from "../../helpers/networkLogger/index.js"; +import { responseStatus } from "../../helpers/assertions/index.js"; +import createFixture from "../../helpers/createFixture/index.js"; +import deviceContextConfig from "../../helpers/constants/deviceContextConfig.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; +import { TEST_PAGE as TEST_PAGE_URL } from "../../helpers/constants/url.js"; +import isUserAgentClientHintsSupported from "../../helpers/isUserAgentClientHintsSupported.js"; + +const networkLogger = createNetworkLogger(); + +const ID = "C2599"; +const DESCRIPTION = `${ID} - Adds only device context data when only device is specified in configuration.`; + +createFixture({ + title: DESCRIPTION, + requestHooks: [networkLogger.edgeEndpointLogs], +}); + +test.meta({ + ID, + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +const sendEventOptions = { + xdm: { + web: { + webPageDetails: { + URL: TEST_PAGE_URL, + }, + }, + }, +}; + +test(DESCRIPTION, async () => { + const alloy = createAlloyProxy(); + await alloy.configure(deviceContextConfig); + await alloy.sendEvent(sendEventOptions); + + await responseStatus(networkLogger.edgeEndpointLogs.requests, [200, 207]); + await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(1); + + const parsedBody = JSON.parse( + networkLogger.edgeEndpointLogs.requests[0].request.body, + ); + + await t.expect(parsedBody.events[0].xdm.device).ok(); + await t.expect(parsedBody.events[0].xdm.web.webPageDetails).ok(); + await t.expect(parsedBody.events[0].xdm.placeContext).notOk(); + await t.expect(parsedBody.events[0].xdm.environment).notOk(); + if (await isUserAgentClientHintsSupported()) { + await t + .expect( + parsedBody.events[0].xdm?.environment?.browserDetails + ?.userAgentClientHints, + ) + .notOk(); + } +}); diff --git a/packages/browser/test/functional/specs/Context/C2600.js b/packages/browser/test/functional/specs/Context/C2600.js new file mode 100644 index 000000000..14b45bf16 --- /dev/null +++ b/packages/browser/test/functional/specs/Context/C2600.js @@ -0,0 +1,71 @@ +/* +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 } from "testcafe"; +import createNetworkLogger from "../../helpers/networkLogger/index.js"; +import { responseStatus } from "../../helpers/assertions/index.js"; +import createFixture from "../../helpers/createFixture/index.js"; +import environmentContextConfig from "../../helpers/constants/environmentContextConfig.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; +import { TEST_PAGE as TEST_PAGE_URL } from "../../helpers/constants/url.js"; +import isUserAgentClientHintsSupported from "../../helpers/isUserAgentClientHintsSupported.js"; + +const networkLogger = createNetworkLogger(); + +const ID = "C2600"; +const DESCRIPTION = `${ID} - Adds only environment context data when only device is specified in configuration.`; + +createFixture({ + title: DESCRIPTION, + requestHooks: [networkLogger.edgeEndpointLogs], +}); + +test.meta({ + ID, + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +const sendEventOptions = { + xdm: { + web: { + webPageDetails: { + URL: TEST_PAGE_URL, + }, + }, + }, +}; + +test(DESCRIPTION, async () => { + const alloy = createAlloyProxy(); + await alloy.configure(environmentContextConfig); + await alloy.sendEvent(sendEventOptions); + + await responseStatus(networkLogger.edgeEndpointLogs.requests, [200, 207]); + await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(1); + + const parsedBody = JSON.parse( + networkLogger.edgeEndpointLogs.requests[0].request.body, + ); + + await t.expect(parsedBody.events[0].xdm.environment).ok(); + await t.expect(parsedBody.events[0].xdm.web.webPageDetails).ok(); + await t.expect(parsedBody.events[0].xdm.device).notOk(); + await t.expect(parsedBody.events[0].xdm.placeContext).notOk(); + if (await isUserAgentClientHintsSupported()) { + await t + .expect( + parsedBody.events[0].xdm?.environment?.browserDetails + ?.userAgentClientHints, + ) + .notOk(); + } +}); diff --git a/packages/browser/test/functional/specs/Context/C2601.js b/packages/browser/test/functional/specs/Context/C2601.js new file mode 100644 index 000000000..5c98f9c90 --- /dev/null +++ b/packages/browser/test/functional/specs/Context/C2601.js @@ -0,0 +1,71 @@ +/* +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 } from "testcafe"; +import createNetworkLogger from "../../helpers/networkLogger/index.js"; +import { responseStatus } from "../../helpers/assertions/index.js"; +import createFixture from "../../helpers/createFixture/index.js"; +import placeContextConfig from "../../helpers/constants/placeContextConfig.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; +import { TEST_PAGE as TEST_PAGE_URL } from "../../helpers/constants/url.js"; +import isUserAgentClientHintsSupported from "../../helpers/isUserAgentClientHintsSupported.js"; + +const networkLogger = createNetworkLogger(); + +const ID = "C2601"; +const DESCRIPTION = `${ID} - Adds only placeContext context data when only device is specified in configuration.`; + +createFixture({ + title: DESCRIPTION, + requestHooks: [networkLogger.edgeEndpointLogs], +}); + +test.meta({ + ID, + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +const sendEventOptions = { + xdm: { + web: { + webPageDetails: { + URL: TEST_PAGE_URL, + }, + }, + }, +}; + +test(DESCRIPTION, async () => { + const alloy = createAlloyProxy(); + await alloy.configure(placeContextConfig); + await alloy.sendEvent(sendEventOptions); + + await responseStatus(networkLogger.edgeEndpointLogs.requests, [200, 207]); + await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(1); + + const parsedBody = JSON.parse( + networkLogger.edgeEndpointLogs.requests[0].request.body, + ); + + await t.expect(parsedBody.events[0].xdm.placeContext).ok(); + await t.expect(parsedBody.events[0].xdm.web.webPageDetails).ok(); + await t.expect(parsedBody.events[0].xdm.environment).notOk(); + await t.expect(parsedBody.events[0].xdm.device).notOk(); + if (await isUserAgentClientHintsSupported()) { + await t + .expect( + parsedBody.events[0].xdm?.environment?.browserDetails + ?.userAgentClientHints, + ) + .notOk(); + } +}); diff --git a/packages/browser/test/functional/specs/Context/C7311732.js b/packages/browser/test/functional/specs/Context/C7311732.js new file mode 100644 index 000000000..29567a814 --- /dev/null +++ b/packages/browser/test/functional/specs/Context/C7311732.js @@ -0,0 +1,71 @@ +/* +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 } from "testcafe"; +import createNetworkLogger from "../../helpers/networkLogger/index.js"; +import { responseStatus } from "../../helpers/assertions/index.js"; +import createFixture from "../../helpers/createFixture/index.js"; +import highEntropyUserAgentHintsContextConfig from "../../helpers/constants/highEntropyUserAgentHintsContextConfig.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; +import { TEST_PAGE as TEST_PAGE_URL } from "../../helpers/constants/url.js"; +import isUserAgentClientHintsSupported from "../../helpers/isUserAgentClientHintsSupported.js"; + +const networkLogger = createNetworkLogger(); + +const ID = "C7311732"; +const DESCRIPTION = `${ID} - Adds only userAgentClientHints context data when only highEntropyUserAgentHints is specified in configuration.`; + +createFixture({ + title: DESCRIPTION, + requestHooks: [networkLogger.edgeEndpointLogs], +}); + +test.meta({ + ID, + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +const sendEventOptions = { + xdm: { + web: { + webPageDetails: { + URL: TEST_PAGE_URL, + }, + }, + }, +}; + +test(DESCRIPTION, async () => { + const alloy = createAlloyProxy(); + await alloy.configure(highEntropyUserAgentHintsContextConfig); + await alloy.sendEvent(sendEventOptions); + + await responseStatus(networkLogger.edgeEndpointLogs.requests, [200, 207]); + await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(1); + + const parsedBody = JSON.parse( + networkLogger.edgeEndpointLogs.requests[0].request.body, + ); + + await t.expect(parsedBody.events[0].xdm.placeContext).notOk(); + await t.expect(parsedBody.events[0].xdm.web.webPageDetails).ok(); + await t.expect(parsedBody.events[0].xdm.device).notOk(); + if (await isUserAgentClientHintsSupported()) { + await t.expect(parsedBody.events[0].xdm.environment.type).notOk(); + await t + .expect( + parsedBody.events[0].xdm.environment.browserDetails + .userAgentClientHints, + ) + .ok(); + } +}); diff --git a/packages/browser/test/functional/specs/Data Collector/C11693274.js b/packages/browser/test/functional/specs/Data Collector/C11693274.js new file mode 100644 index 000000000..961f205c2 --- /dev/null +++ b/packages/browser/test/functional/specs/Data Collector/C11693274.js @@ -0,0 +1,69 @@ +/* +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, Selector } from "testcafe"; +import createFixture from "../../helpers/createFixture/index.js"; +import addHtmlToBody from "../../helpers/dom/addHtmlToBody.js"; +import { + compose, + orgMainConfigMain, + clickCollectionEnabled, +} from "../../helpers/constants/configParts/index.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; +import preventLinkNavigation from "../../helpers/preventLinkNavigation.js"; +import createCollectEndpointAsserter from "../../helpers/createCollectEndpointAsserter.js"; + +createFixture({ + title: "C11693274: Does not search query parameters to qualify exit links.", +}); + +test.meta({ + ID: "C11693274", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +const addLinkToBody = () => { + return addHtmlToBody( + `Test Link`, + ); +}; + +const clickLink = async () => { + await t.click(Selector("#alloy-link-test")); +}; + +const assertRequestXdm = async (request) => { + const requestBody = JSON.parse(request.request.body); + const eventXdm = requestBody.events[0].xdm; + await t.expect(eventXdm.eventType).eql("web.webinteraction.linkClicks"); + await t.expect(eventXdm.web.webInteraction).eql({ + name: "Test Link", + region: "BODY", + type: "exit", + URL: "https://example.com/?exclude-this=alloyio.com", + linkClicks: { value: 1 }, + }); +}; + +test("Test C11693274: Verify URL query does not affect determining exit link type", async () => { + const collectEndpointAsserter = await createCollectEndpointAsserter(); + await preventLinkNavigation(); + const alloy = createAlloyProxy(); + const testConfig = compose(orgMainConfigMain, clickCollectionEnabled); + await alloy.configure(testConfig); + await addLinkToBody(); + await clickLink(); + await collectEndpointAsserter.assertInteractCalledAndNotCollect(); + const interactRequest = await collectEndpointAsserter.getInteractRequest(); + await collectEndpointAsserter.reset(); + await assertRequestXdm(interactRequest); +}); diff --git a/packages/browser/test/functional/specs/Data Collector/C1715149.js b/packages/browser/test/functional/specs/Data Collector/C1715149.js new file mode 100644 index 000000000..c46488f16 --- /dev/null +++ b/packages/browser/test/functional/specs/Data Collector/C1715149.js @@ -0,0 +1,100 @@ +/* +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 createNetworkLogger from "../../helpers/networkLogger/index.js"; +import createFixture from "../../helpers/createFixture/index.js"; +import { + debugEnabled, + orgMainConfigMain, +} from "../../helpers/constants/configParts/index.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; +import createConsoleLogger from "../../helpers/consoleLogger/index.js"; + +const networkLogger = createNetworkLogger(); + +const onBeforeEventSend = ClientFunction((content) => { + window.onBeforeEventSendCalled = true; + content.xdm.foo = "bar"; +}); + +const onBeforeEventSendFailed = ClientFunction(() => { + window.onBeforeEventSendCalled = true; + throw new Error("Expected Error"); +}); + +const onBeforeEventSendFalse = ClientFunction(() => { + window.onBeforeEventSendCalled = true; + return false; +}); + +const getOnBeforeEventSendCalled = ClientFunction(() => { + return window.onBeforeEventSendCalled === true; +}); + +createFixture({ + title: + "C1715149 sendEvent should call onBeforeEventSend callback and send when expected", + requestHooks: [networkLogger.edgeInteractEndpointLogs], +}); + +test.meta({ + ID: "C1715149", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +test("C1715149 Events should call onBeforeEventSend callback and still send event", async () => { + const alloy = createAlloyProxy(); + await alloy.configure({ + ...orgMainConfigMain, + onBeforeEventSend, + }); + await alloy.sendEvent(); + + await t.expect(getOnBeforeEventSendCalled()).eql(true); + const request = + networkLogger.edgeInteractEndpointLogs.requests[0].request.body; + const parsedRequest = JSON.parse(request); + await t.expect(parsedRequest.events[0].xdm.foo).eql("bar"); +}); + +test("C1715149 Events should call onBeforeEventSend callback, fail, and not send event", async () => { + const alloy = createAlloyProxy(); + await alloy.configure({ + ...orgMainConfigMain, + onBeforeEventSend: onBeforeEventSendFailed, + }); + const errorMessage = await alloy.sendEventErrorMessage(); + + await t.expect(getOnBeforeEventSendCalled()).eql(true); + await t.expect(errorMessage).match(/Expected Error/); + await t.expect(networkLogger.edgeInteractEndpointLogs.requests.length).eql(0); +}); + +test("C1715149 Events should call onBeforeEventSend callback, return false, and not send event", async () => { + const logger = await createConsoleLogger(); + const alloy = createAlloyProxy(); + await alloy.configure({ + ...orgMainConfigMain, + ...debugEnabled, + onBeforeEventSend: onBeforeEventSendFalse, + }); + + const result = await alloy.sendEvent(); + + await t.expect(getOnBeforeEventSendCalled()).eql(true); + + // if event is cancelled, the promise should resolve with an empty object + await t.expect(result).eql({}); + await t.expect(networkLogger.edgeInteractEndpointLogs.requests.length).eql(0); + await logger.info.expectMessageMatching(/Event was canceled/); +}); diff --git a/packages/browser/test/functional/specs/Data Collector/C225010.js b/packages/browser/test/functional/specs/Data Collector/C225010.js new file mode 100644 index 000000000..9a950221f --- /dev/null +++ b/packages/browser/test/functional/specs/Data Collector/C225010.js @@ -0,0 +1,61 @@ +/* +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, Selector, ClientFunction } from "testcafe"; +import createFixture from "../../helpers/createFixture/index.js"; +import addHtmlToBody from "../../helpers/dom/addHtmlToBody.js"; +import createConsoleLogger from "../../helpers/consoleLogger/index.js"; +import createUnhandledRejectionLogger from "../../helpers/createUnhandledRejectionLogger.js"; +import { + compose, + orgMainConfigMain, + consentPending, + debugEnabled, + clickCollectionEnabled, + clickCollectionEventGroupingDisabled, +} from "../../helpers/constants/configParts/index.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; +import { CONSENT_OUT } from "../../helpers/constants/consent.js"; + +createFixture({ + title: "C225010: Click collection handles errors when user declines consent", +}); + +test.meta({ + ID: "C8118", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +test("Test C225010: Click collection handles errors when user declines consent", async () => { + const alloy = createAlloyProxy(); + const getLocation = ClientFunction(() => document.location.href.toString()); + const testConfig = compose( + orgMainConfigMain, + consentPending, + debugEnabled, + clickCollectionEnabled, + clickCollectionEventGroupingDisabled, + ); + await alloy.configure(testConfig); + await alloy.setConsent(CONSENT_OUT); + + await addHtmlToBody(`Test Link`); + + const consoleLogger = await createConsoleLogger(); + const unhandledRejectionLogger = await createUnhandledRejectionLogger(); + await t.click(Selector("#alloy-link-test")); + await t.expect(getLocation()).contains("#foo"); + await consoleLogger.warn.expectMessageMatching( + /The click collection could not fully complete. The user declined consent./, + ); + await unhandledRejectionLogger.expectNoMessageMatching(/.*/); +}); diff --git a/packages/browser/test/functional/specs/Data Collector/C2592.js b/packages/browser/test/functional/specs/Data Collector/C2592.js new file mode 100644 index 000000000..891bbdba8 --- /dev/null +++ b/packages/browser/test/functional/specs/Data Collector/C2592.js @@ -0,0 +1,63 @@ +/* +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 } from "testcafe"; +import createNetworkLogger from "../../helpers/networkLogger/index.js"; +import { responseStatus } from "../../helpers/assertions/index.js"; +import createFixture from "../../helpers/createFixture/index.js"; +import { + compose, + configOverridesMain, + orgMainConfigMain, + debugEnabled, +} from "../../helpers/constants/configParts/index.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; + +const networkLogger = createNetworkLogger(); +const config = compose(orgMainConfigMain, debugEnabled); + +createFixture({ + title: "C2592: Event command sends a request", + requestHooks: [networkLogger.edgeEndpointLogs], +}); + +test.meta({ + ID: "C2592", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +test("Test C2592: Event command sends a request.", async () => { + const alloy = createAlloyProxy(); + await alloy.configure(config); + await alloy.sendEvent({ + datasetId: + configOverridesMain.com_adobe_experience_platform.datasets.event + .datasetId, + }); + + await responseStatus(networkLogger.edgeEndpointLogs.requests, [200, 207]); + + await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(1); + + const request = JSON.parse( + networkLogger.edgeEndpointLogs.requests[0].request.body, + ); + + await t + .expect(request.events[0].xdm.implementationDetails.name) + .eql("https://ns.adobe.com/experience/alloy"); + await t + .expect(request.meta.configOverrides.com_adobe_experience_platform.event) + .eql(configOverridesMain.com_adobe_experience_platform.event); + await t.expect(request.meta.state.cookiesEnabled).eql(true); + await t.expect(request.meta.state.domain).ok(); +}); diff --git a/packages/browser/test/functional/specs/Data Collector/C455258.js b/packages/browser/test/functional/specs/Data Collector/C455258.js new file mode 100644 index 000000000..ef8646c56 --- /dev/null +++ b/packages/browser/test/functional/specs/Data Collector/C455258.js @@ -0,0 +1,49 @@ +/* +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 createFixture from "../../helpers/createFixture/index.js"; +import { orgMainConfigMain } from "../../helpers/constants/configParts/index.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; +import createCollectEndpointAsserter from "../../helpers/createCollectEndpointAsserter.js"; + +createFixture({ + title: + "C455258: sendEvent command sends a request to the collect endpoint using sendBeacon when documentUnloading is set to true but only when identity has established.", +}); + +test.meta({ + ID: "C455258", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +test("Test C455258: sendEvent command sends a request to the collect endpoint when identity has been established and documentUnloading is set to true, interact otherwise.", async () => { + const collectEndpointAsserter = await createCollectEndpointAsserter(); + const alloy = createAlloyProxy(); + await alloy.configure(orgMainConfigMain); + + // An identity has not yet been established. This request should go to the + // interact endpoint. + await alloy.sendEvent({ documentUnloading: true }); + await collectEndpointAsserter.assertInteractCalledAndNotCollect(); + await collectEndpointAsserter.reset(); + + // An identity has been established. This request should go to the + // collect endpoint. + await alloy.sendEvent({ documentUnloading: true }); + await collectEndpointAsserter.assertCollectCalledAndNotInteract(); + await collectEndpointAsserter.reset(); + + // documentUnloading is not set to true. The request should go to the + // interact endpoint. + await alloy.sendEvent(); + await collectEndpointAsserter.assertInteractCalledAndNotCollect(); +}); diff --git a/packages/browser/test/functional/specs/Data Collector/C75372.js b/packages/browser/test/functional/specs/Data Collector/C75372.js new file mode 100644 index 000000000..c891d8380 --- /dev/null +++ b/packages/browser/test/functional/specs/Data Collector/C75372.js @@ -0,0 +1,57 @@ +/* +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 createNetworkLogger from "../../helpers/networkLogger/index.js"; +import createFixture from "../../helpers/createFixture/index.js"; +import { orgMainConfigMain } from "../../helpers/constants/configParts/index.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; + +const networkLogger = createNetworkLogger(); + +createFixture({ + title: + "C75372 - XDM and data objects passed into event command should not be modified", + requestHooks: [networkLogger.setConsentEndpointLogs], +}); + +test.meta({ + ID: "C75372", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +const sendEvent = ClientFunction(() => { + const xdmDataLayer = { device: { screenHeight: 1 } }; + const nonXdmDataLayer = { baz: "quux" }; + // Using a merge ID is a decent test because it's one thing we know + // gets merged with the XDM object. + return window + .alloy("sendEvent", { + xdm: xdmDataLayer, + data: nonXdmDataLayer, + mergeId: "abc", + }) + .then(() => { + return { + xdmDataLayer, + nonXdmDataLayer, + }; + }); +}); + +test("C75372 - XDM and data objects passed into event command should not be modified", async () => { + const alloy = createAlloyProxy(); + await alloy.configure(orgMainConfigMain); + const { xdmDataLayer, nonXdmDataLayer } = await sendEvent(); + await t.expect(xdmDataLayer).eql({ device: { screenHeight: 1 } }); + await t.expect(nonXdmDataLayer).eql({ baz: "quux" }); +}); diff --git a/packages/browser/test/functional/specs/Data Collector/C8118.js b/packages/browser/test/functional/specs/Data Collector/C8118.js new file mode 100644 index 000000000..9a22c8e54 --- /dev/null +++ b/packages/browser/test/functional/specs/Data Collector/C8118.js @@ -0,0 +1,503 @@ +/* +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, Selector } from "testcafe"; +import createFixture from "../../helpers/createFixture/index.js"; +import addHtmlToBody from "../../helpers/dom/addHtmlToBody.js"; +import { + compose, + orgMainConfigMain, + clickCollectionEnabled, + clickCollectionEventGroupingDisabled, +} from "../../helpers/constants/configParts/index.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; +import preventLinkNavigation from "../../helpers/preventLinkNavigation.js"; +import createCollectEndpointAsserter from "../../helpers/createCollectEndpointAsserter.js"; + +createFixture({ + title: "C8118: Collects and sends information about link clicks.", +}); + +test.meta({ + ID: "C8118", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +const INTERNAL_LINK_ANCHOR_1 = `Test Link`; +const INTERNAL_LINK_ANCHOR_2 = `Internal Link`; +const DOWNLOAD_LINK_ANCHOR = `Download Zip File`; +const EXTERNAL_LINK_ANCHOR = `External Link`; + +const addLinkToBody = (link) => { + return addHtmlToBody(`${link}`); +}; + +const clickLink = async () => { + await t.click(Selector("#alloy-link-test")); +}; + +const getEventTypeFromRequest = (req) => { + const bodyJson = JSON.parse(req.request.body); + return bodyJson.events[0].xdm.eventType; +}; + +const getWebInteractionFromRequest = (req) => { + const bodyJson = JSON.parse(req.request.body); + return bodyJson.events[0].xdm.web.webInteraction; +}; + +const getXdmFromRequest = (req) => { + const bodyJson = JSON.parse(req.request.body); + return bodyJson.events[0].xdm; +}; + +/* eslint no-underscore-dangle: 0 */ +const getActivityMapDataFromRequest = (req) => { + const bodyJson = JSON.parse(req.request.body); + return bodyJson.events[0].data.__adobe.analytics.contextData.a.activitymap; +}; + +const assertRequestXdm = async (req) => { + const eventType = getEventTypeFromRequest(req); + await t.expect(eventType).eql("web.webinteraction.linkClicks"); + const webInteraction = getWebInteractionFromRequest(req); + await t.expect(webInteraction).eql({ + name: "Test Link", + region: "BODY", + type: "other", + URL: "https://alloyio.com/functional-test/blank.html", + linkClicks: { value: 1 }, + }); +}; + +test("Test C8118: Verify link click sends a request to the collect endpoint when identity has been established, interact endpoint otherwise", async () => { + const testConfig = compose( + orgMainConfigMain, + clickCollectionEnabled, + clickCollectionEventGroupingDisabled, // To prevent internal link click to get cached + ); + const collectEndpointAsserter = await createCollectEndpointAsserter(); + const alloy = createAlloyProxy(); + await alloy.configure(testConfig); + await preventLinkNavigation(); + await addLinkToBody(INTERNAL_LINK_ANCHOR_1); + await clickLink(); + await collectEndpointAsserter.assertInteractCalledAndNotCollect(); + const interactRequest = await collectEndpointAsserter.getInteractRequest(); + await collectEndpointAsserter.reset(); + // If an identity has not been established, we hit the interact endpoint using + // fetch even though the user may be navigating away from the page. In the + // real world where we're not blocking navigation, Alloy may + // or may not get a response back before navigation completes. If Alloy does not + // receive a response back, an identity cookie will not have been established, unfortunately, + // but that is considered better than using sendBeacon that for sure would not establish + // an identity. + await assertRequestXdm(interactRequest); + + // Because an identity has been established, we can safely hit the collect + // endpoint using sendBeacon. + await clickLink(); + await collectEndpointAsserter.assertCollectCalledAndNotInteract(); +}); + +test("Test C8118: Verify that a download link click data is not sent when download link click collection is disabled", async () => { + const testConfig = compose(orgMainConfigMain, clickCollectionEnabled, { + clickCollection: { + downloadLinkEnabled: false, + eventGroupingEnabled: false, + }, + }); + const collectEndpointAsserter = await createCollectEndpointAsserter(); + const alloy = createAlloyProxy(); + await alloy.configure(testConfig); + await preventLinkNavigation(); + await addLinkToBody(DOWNLOAD_LINK_ANCHOR); + await clickLink(); + await collectEndpointAsserter.assertNeitherCollectNorInteractCalled(); +}); + +test("Test C8118: Verify that a download link click data is sent when download link click collection is enabled", async () => { + const testConfig = compose(orgMainConfigMain, clickCollectionEnabled, { + clickCollection: { + downloadLinkEnabled: true, + eventGroupingEnabled: false, + }, + }); + const collectEndpointAsserter = await createCollectEndpointAsserter(); + const alloy = createAlloyProxy(); + await alloy.configure(testConfig); + await preventLinkNavigation(); + await addLinkToBody(DOWNLOAD_LINK_ANCHOR); + await clickLink(); + await collectEndpointAsserter.assertInteractCalledAndNotCollect(); + const interactRequest = await collectEndpointAsserter.getInteractRequest(); + const webInteraction = await getWebInteractionFromRequest(interactRequest); + await t.expect(webInteraction).eql({ + name: "Download Zip File", + region: "BODY", + type: "download", + URL: "https://alloyio.com/functional-test/example.zip", + linkClicks: { value: 1 }, + }); + const activityMapData = getActivityMapDataFromRequest(interactRequest); + await t.expect(activityMapData).eql({ + page: "https://alloyio.com/functional-test/testPage.html", + link: "Download Zip File", + region: "BODY", + pageIDType: 0, + }); +}); + +test("Test C8118: Verify that a internal link click data is not sent when internal link click collection is disabled", async () => { + const testConfig = compose(orgMainConfigMain, clickCollectionEnabled, { + clickCollection: { + internalLinkEnabled: false, + eventGroupingEnabled: false, + }, + }); + const collectEndpointAsserter = await createCollectEndpointAsserter(); + const alloy = createAlloyProxy(); + await alloy.configure(testConfig); + await preventLinkNavigation(); + await addLinkToBody(INTERNAL_LINK_ANCHOR_1); + await clickLink(); + await collectEndpointAsserter.assertNeitherCollectNorInteractCalled(); +}); + +test("Test C8118: Verify that a internal link click data is sent when internal link click collection is enabled", async () => { + const testConfig = compose(orgMainConfigMain, clickCollectionEnabled, { + clickCollection: { + internalLinkEnabled: true, + eventGroupingEnabled: false, + }, + }); + const collectEndpointAsserter = await createCollectEndpointAsserter(); + const alloy = createAlloyProxy(); + await alloy.configure(testConfig); + await preventLinkNavigation(); + await addLinkToBody(INTERNAL_LINK_ANCHOR_2); + await clickLink(); + await collectEndpointAsserter.assertInteractCalledAndNotCollect(); + const interactRequest = await collectEndpointAsserter.getInteractRequest(); + const webInteraction = await getWebInteractionFromRequest(interactRequest); + await t.expect(webInteraction).eql({ + name: "Internal Link", + region: "BODY", + type: "other", + URL: "https://alloyio.com/functional-test/blank.html", + linkClicks: { value: 1 }, + }); + const activityMapData = getActivityMapDataFromRequest(interactRequest); + await t.expect(activityMapData).eql({ + page: "https://alloyio.com/functional-test/testPage.html", + link: "Internal Link", + region: "BODY", + pageIDType: 0, + }); +}); + +test("Test C8118: Verify that a external link click data is not sent when external link click collection is disabled", async () => { + const testConfig = compose(orgMainConfigMain, clickCollectionEnabled, { + clickCollection: { + externalLinkEnabled: false, + eventGroupingEnabled: false, + }, + }); + const collectEndpointAsserter = await createCollectEndpointAsserter(); + const alloy = createAlloyProxy(); + await alloy.configure(testConfig); + await preventLinkNavigation(); + await addLinkToBody(EXTERNAL_LINK_ANCHOR); + await clickLink(); + await collectEndpointAsserter.assertNeitherCollectNorInteractCalled(); +}); + +test("Test C8118: Verify that a external link click data is sent when external link click collection is enabled", async () => { + const testConfig = compose(orgMainConfigMain, clickCollectionEnabled, { + clickCollection: { + externalLinkEnabled: true, + eventGroupingEnabled: false, + }, + }); + const collectEndpointAsserter = await createCollectEndpointAsserter(); + const alloy = createAlloyProxy(); + await alloy.configure(testConfig); + await preventLinkNavigation(); + await addLinkToBody(EXTERNAL_LINK_ANCHOR); + await clickLink(); + await collectEndpointAsserter.assertInteractCalledAndNotCollect(); + const interactRequest = await collectEndpointAsserter.getInteractRequest(); + const webInteraction = await getWebInteractionFromRequest(interactRequest); + await t.expect(webInteraction).eql({ + name: "External Link", + region: "BODY", + type: "exit", + URL: "https://example.com/", + linkClicks: { value: 1 }, + }); + const activityMapData = getActivityMapDataFromRequest(interactRequest); + await t.expect(activityMapData).eql({ + page: "https://alloyio.com/functional-test/testPage.html", + link: "External Link", + region: "BODY", + pageIDType: 0, + }); +}); + +test("Test C8118: Verify that a internal link click data is not sent when event grouping is enabled", async () => { + const testConfig = compose(orgMainConfigMain, clickCollectionEnabled, { + clickCollection: { + internalLinkEnabled: true, + eventGroupingEnabled: true, + }, + }); + const collectEndpointAsserter = await createCollectEndpointAsserter(); + const alloy = createAlloyProxy(); + await alloy.configure(testConfig); + await preventLinkNavigation(); + await addLinkToBody(INTERNAL_LINK_ANCHOR_1); + await clickLink(); + await collectEndpointAsserter.assertNeitherCollectNorInteractCalled(); +}); + +test("Test C8118: Verify cached internal link click data is sent on the next page view event", async () => { + const testConfig = compose(orgMainConfigMain, clickCollectionEnabled, { + clickCollection: { + internalLinkEnabled: true, + eventGroupingEnabled: true, + }, + }); + const collectEndpointAsserter = await createCollectEndpointAsserter(); + const alloy = createAlloyProxy(); + await alloy.configure(testConfig); + await preventLinkNavigation(); + await addLinkToBody(INTERNAL_LINK_ANCHOR_1); + await clickLink(); + await collectEndpointAsserter.assertNeitherCollectNorInteractCalled(); + await collectEndpointAsserter.reset(); + await alloy.sendEvent({ + xdm: { + web: { + eventType: "web.webpagedetails.pageViews", + webPageDetails: { + name: "Test Page", + pageViews: { + value: 1, + }, + }, + }, + }, + }); + await collectEndpointAsserter.assertInteractCalledAndNotCollect(); + const interactRequest = await collectEndpointAsserter.getInteractRequest(); + const xdm = await getXdmFromRequest(interactRequest); + await t.expect(xdm.web.webInteraction).eql({ + name: "Test Link", + region: "BODY", + type: "other", + URL: "https://alloyio.com/functional-test/blank.html", + linkClicks: { value: 1 }, + }); + await t.expect(xdm.web.webPageDetails).eql({ + URL: "https://alloyio.com/functional-test/testPage.html", + name: "Test Page", + pageViews: { value: 1 }, + }); + const activityMapData = getActivityMapDataFromRequest(interactRequest); + await t.expect(activityMapData).eql({ + page: "https://alloyio.com/functional-test/testPage.html", + link: "Test Link", + region: "BODY", + pageIDType: 0, + }); +}); + +test("Test C8118: Verify internal link click data with custom region", async () => { + const testConfig = compose(orgMainConfigMain, clickCollectionEnabled, { + clickCollection: { + internalLinkEnabled: true, + eventGroupingEnabled: false, + }, + }); + const collectEndpointAsserter = await createCollectEndpointAsserter(); + const alloy = createAlloyProxy(); + await alloy.configure(testConfig); + await preventLinkNavigation(); + await addHtmlToBody( + '', + ); + await clickLink(); + await collectEndpointAsserter.assertInteractCalledAndNotCollect(); + const interactRequest = await collectEndpointAsserter.getInteractRequest(); + const webInteraction = await getWebInteractionFromRequest(interactRequest); + await t.expect(webInteraction.region).eql("custom-region"); +}); + +test("Test C8118: Verify external link click data with custom link type", async () => { + const testConfig = compose(orgMainConfigMain, clickCollectionEnabled, { + clickCollection: { + externalLinkEnabled: true, + eventGroupingEnabled: false, + }, + }); + const collectEndpointAsserter = await createCollectEndpointAsserter(); + const alloy = createAlloyProxy(); + await alloy.configure(testConfig); + await preventLinkNavigation(); + await addLinkToBody( + 'External Link', + ); + await clickLink(); + await collectEndpointAsserter.assertInteractCalledAndNotCollect(); + const interactRequest = await collectEndpointAsserter.getInteractRequest(); + const webInteraction = await getWebInteractionFromRequest(interactRequest); + await t.expect(webInteraction.type).eql("exit"); +}); + +test("Test C8118: Verify link click with custom activity map data", async () => { + const testConfig = compose(orgMainConfigMain, clickCollectionEnabled, { + clickCollection: { + internalLinkEnabled: true, + eventGroupingEnabled: false, + }, + }); + const collectEndpointAsserter = await createCollectEndpointAsserter(); + const alloy = createAlloyProxy(); + await alloy.configure(testConfig); + await preventLinkNavigation(); + await addHtmlToBody( + '', + ); + await clickLink(); + await collectEndpointAsserter.assertInteractCalledAndNotCollect(); + const interactRequest = await collectEndpointAsserter.getInteractRequest(); + const activityMapData = getActivityMapDataFromRequest(interactRequest); + + // Check each property individually + await t + .expect(activityMapData.page) + .eql("https://alloyio.com/functional-test/testPage.html"); + await t.expect(activityMapData.link).eql("Custom Activity Map Link"); + await t.expect(activityMapData.region).eql("custom-region"); + await t.expect(activityMapData.pageIDType).eql(0); + + // If all individual checks pass, then do the full object comparison + await t.expect(activityMapData).eql({ + page: "https://alloyio.com/functional-test/testPage.html", + link: "Custom Activity Map Link", + region: "custom-region", + pageIDType: 0, + }); +}); + +test("Test C8118: Verify multiple link clicks with event grouping enabled", async () => { + const testConfig = compose(orgMainConfigMain, clickCollectionEnabled, { + clickCollection: { + internalLinkEnabled: true, + eventGroupingEnabled: true, + }, + }); + const collectEndpointAsserter = await createCollectEndpointAsserter(); + const alloy = createAlloyProxy(); + await alloy.configure(testConfig); + await preventLinkNavigation(); + await addLinkToBody('Link 1'); + await addLinkToBody('Link 2'); + + await t.click(Selector("#alloy-link-test-1")); + await t.click(Selector("#alloy-link-test-2")); + + await collectEndpointAsserter.assertNeitherCollectNorInteractCalled(); + await collectEndpointAsserter.reset(); + + await alloy.sendEvent({ + xdm: { + web: { + eventType: "web.webpagedetails.pageViews", + webPageDetails: { + name: "Test Page", + pageViews: { value: 1 }, + }, + }, + }, + }); + + await collectEndpointAsserter.assertInteractCalledAndNotCollect(); + const interactRequest = await collectEndpointAsserter.getInteractRequest(); + const xdm = await getXdmFromRequest(interactRequest); + + if (Array.isArray(xdm.web.webInteraction)) { + await t.expect(xdm.web.webInteraction.length).eql(2); + await t.expect(xdm.web.webInteraction[0].name).eql("Link 1"); + await t.expect(xdm.web.webInteraction[1].name).eql("Link 2"); + } else if (xdm.web.webInteraction) { + await t.expect(xdm.web.webInteraction.name).eql("Link 2"); + } else { + await t.fail("No webInteraction data found in XDM"); + } +}); + +test("Test C8118: Verify link click with custom XDM data", async () => { + const testConfig = compose(orgMainConfigMain, clickCollectionEnabled, { + clickCollection: { + internalLinkEnabled: true, + eventGroupingEnabled: false, + }, + onBeforeLinkClickSend: (options) => { + options.xdm.customField = "customValue"; + return true; + }, + }); + const collectEndpointAsserter = await createCollectEndpointAsserter(); + const alloy = createAlloyProxy(); + await alloy.configure(testConfig); + await preventLinkNavigation(); + await addLinkToBody(INTERNAL_LINK_ANCHOR_2); + + await clickLink(); + await collectEndpointAsserter.assertInteractCalledAndNotCollect(); + const interactRequest = await collectEndpointAsserter.getInteractRequest(); + const xdm = await getXdmFromRequest(interactRequest); + await t.expect(xdm.customField).eql("customValue"); +}); + +test("Test C8118: Verify storePageViewProperties functionality", async () => { + const testConfig = compose(orgMainConfigMain, clickCollectionEnabled, { + clickCollection: { + eventGroupingEnabled: true, + }, + }); + const collectEndpointAsserter = await createCollectEndpointAsserter(); + const alloy = createAlloyProxy(); + await alloy.configure(testConfig); + await preventLinkNavigation(); + await addLinkToBody(INTERNAL_LINK_ANCHOR_1); + await clickLink(); + + await alloy.sendEvent({ + xdm: { + web: { + webPageDetails: { + name: "Test Page", + }, + }, + }, + }); + + await collectEndpointAsserter.assertInteractCalledAndNotCollect(); + const interactRequest = await collectEndpointAsserter.getInteractRequest(); + const xdm = await getXdmFromRequest(interactRequest); + await t.expect(xdm.web.webPageDetails.name).eql("Test Page"); + await t + .expect(xdm.web.webInteraction) + .ok("Web interaction should be present"); +}); diff --git a/packages/browser/test/functional/specs/Data Collector/C81181.js b/packages/browser/test/functional/specs/Data Collector/C81181.js new file mode 100644 index 000000000..fbed04d41 --- /dev/null +++ b/packages/browser/test/functional/specs/Data Collector/C81181.js @@ -0,0 +1,330 @@ +/* +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, Selector } from "testcafe"; +import createFixture from "../../helpers/createFixture/index.js"; +import addHtmlToBody from "../../helpers/dom/addHtmlToBody.js"; +import { + compose, + orgMainConfigMain, + clickCollectionEnabled, + clickCollectionEventGroupingDisabled, + clickCollectionSessionStorageDisabled, +} from "../../helpers/constants/configParts/index.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; +import preventLinkNavigation from "../../helpers/preventLinkNavigation.js"; +import createCollectEndpointAsserter from "../../helpers/createCollectEndpointAsserter.js"; + +createFixture({ + title: "C81181: Test onBeforeLinkClickSend callback", +}); + +test.meta({ + ID: "C81181", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +const addLinksToBody = () => { + return addHtmlToBody( + `Test Link + Link Click that is canceled`, + ); +}; + +const clickLink = async (selector) => { + await t.click(Selector(selector)); +}; + +const assertRequestXdm = async ( + request, + expectedXdmWebInteraction, + expectedData, +) => { + const requestBody = JSON.parse(request.request.body); + const eventXdm = requestBody.events[0].xdm; + const eventData = requestBody.events[0].data; + await t.expect(eventXdm.eventType).eql("web.webinteraction.linkClicks"); + await t.expect(eventXdm.web.webInteraction).eql(expectedXdmWebInteraction); + if (expectedData) { + await t.expect(eventData).eql(expectedData); + } +}; + +test("Test C81181: Verify that onBeforeLinkClickSend cancels a request", async () => { + const collectEndpointAsserter = await createCollectEndpointAsserter(); + await preventLinkNavigation(); + const alloy = createAlloyProxy(); + + const testConfig = compose(orgMainConfigMain, clickCollectionEnabled, { + onBeforeLinkClickSend: () => { + return false; + }, + }); + await alloy.configure(testConfig); + await addLinksToBody(); + await clickLink("#alloy-link-test"); + await collectEndpointAsserter.assertNeitherCollectNorInteractCalled(); +}); + +test("Test C81181: Verify that filterClickDetails can cancel a request", async () => { + const collectEndpointAsserter = await createCollectEndpointAsserter(); + await preventLinkNavigation(); + const alloy = createAlloyProxy(); + const testConfig = compose(orgMainConfigMain, clickCollectionEnabled, { + clickCollection: { + filterClickDetails: () => { + return false; + }, + }, + }); + await alloy.configure(testConfig); + await addLinksToBody(); + await clickLink("#alloy-link-test"); + await collectEndpointAsserter.assertNeitherCollectNorInteractCalled(); +}); + +test("Test C81181: Verify that if onBeforeLinkClickSend not defined and clickCollectionEnabled link clicks are collected", async () => { + const collectEndpointAsserter = await createCollectEndpointAsserter(); + await preventLinkNavigation(); + const alloy = createAlloyProxy(); + const testConfig = compose( + orgMainConfigMain, + clickCollectionEnabled, + clickCollectionEventGroupingDisabled, + ); + await alloy.configure(testConfig); + await addLinksToBody(); + await clickLink("#alloy-link-test"); + await collectEndpointAsserter.assertInteractCalledAndNotCollect(); + const interactRequest = collectEndpointAsserter.getInteractRequest(); + const expectedXdm = { + name: "Test Link", + region: "BODY", + type: "other", + URL: "https://alloyio.com/functional-test/valid.html", + linkClicks: { value: 1 }, + }; + await assertRequestXdm(interactRequest, expectedXdm); +}); + +test("Test C81181: Verify that onBeforeLinkClickSend cancels a request based on link details", async () => { + const collectEndpointAsserter = await createCollectEndpointAsserter(); + await preventLinkNavigation(); + const alloy = createAlloyProxy(); + + const testConfig = compose( + orgMainConfigMain, + clickCollectionEnabled, + clickCollectionEventGroupingDisabled, + { + onBeforeLinkClickSend: (options) => { + const { clickedElement } = options; + return clickedElement.id !== "canceled-alloy-link-test"; + }, + }, + ); + await alloy.configure(testConfig); + await addLinksToBody(); + await clickLink("#canceled-alloy-link-test"); + await collectEndpointAsserter.assertNeitherCollectNorInteractCalled(); + await clickLink("#alloy-link-test"); + await collectEndpointAsserter.assertInteractCalledAndNotCollect(); + const interactRequest = collectEndpointAsserter.getInteractRequest(); + const expectedXdm = { + name: "Test Link", + region: "BODY", + type: "other", + URL: "https://alloyio.com/functional-test/valid.html", + linkClicks: { value: 1 }, + }; + await assertRequestXdm(interactRequest, expectedXdm); +}); + +test("Test C81181: Verify that filterClickDetails can cancels a request based on link details", async () => { + const collectEndpointAsserter = await createCollectEndpointAsserter(); + await preventLinkNavigation(); + const alloy = createAlloyProxy(); + + const testConfig = compose(orgMainConfigMain, clickCollectionEnabled, { + clickCollection: { + eventGroupingEnabled: false, + filterClickDetails: (props) => { + return props.clickedElement.id !== "canceled-alloy-link-test"; + }, + }, + }); + await alloy.configure(testConfig); + await addLinksToBody(); + await clickLink("#canceled-alloy-link-test"); + await collectEndpointAsserter.assertNeitherCollectNorInteractCalled(); + await clickLink("#alloy-link-test"); + await collectEndpointAsserter.assertInteractCalledAndNotCollect(); + const interactRequest = collectEndpointAsserter.getInteractRequest(); + const expectedXdm = { + name: "Test Link", + region: "BODY", + type: "other", + URL: "https://alloyio.com/functional-test/valid.html", + linkClicks: { value: 1 }, + }; + await assertRequestXdm(interactRequest, expectedXdm); +}); + +test("Test C81181: Verify that onBeforeLinkClickSend augments a request", async () => { + const collectEndpointAsserter = await createCollectEndpointAsserter(); + await preventLinkNavigation(); + const alloy = createAlloyProxy(); + + const testConfig = compose( + orgMainConfigMain, + clickCollectionEnabled, + clickCollectionEventGroupingDisabled, + { + onBeforeLinkClickSend: (options) => { + const { xdm, data, clickedElement } = options; + + if (clickedElement.id === "alloy-link-test") { + xdm.web.webInteraction.name = "Augmented name"; + data.customField = "test123"; + + return true; + } + return false; + }, + }, + ); + + await alloy.configure(testConfig); + await addLinksToBody(); + await clickLink("#canceled-alloy-link-test"); + await collectEndpointAsserter.assertNeitherCollectNorInteractCalled(); + await clickLink("#alloy-link-test"); + await collectEndpointAsserter.assertInteractCalledAndNotCollect(); + const interactRequest = collectEndpointAsserter.getInteractRequest(); + + const expectedXdmWebInteraction = { + name: "Augmented name", + region: "BODY", + type: "other", + URL: "https://alloyio.com/functional-test/valid.html", + linkClicks: { value: 1 }, + }; + + const expectedData = { + __adobe: { + analytics: { + contextData: { + a: { + activitymap: { + link: "Test Link", + page: "https://alloyio.com/functional-test/testPage.html", + pageIDType: 0, + region: "BODY", + }, + }, + }, + }, + }, + customField: "test123", + }; + + await assertRequestXdm( + interactRequest, + expectedXdmWebInteraction, + expectedData, + ); +}); + +test("Test C81181: Verify that filterClickDetails can augment a request", async () => { + const collectEndpointAsserter = await createCollectEndpointAsserter(); + await preventLinkNavigation(); + const alloy = createAlloyProxy(); + + const testConfig = compose(orgMainConfigMain, clickCollectionEnabled, { + clickCollection: { + eventGroupingEnabled: false, + filterClickDetails: (props) => { + if (props.clickedElement.id === "alloy-link-test") { + props.linkName = "Augmented name"; + return true; + } + return false; + }, + }, + }); + + await alloy.configure(testConfig); + await addLinksToBody(); + await clickLink("#canceled-alloy-link-test"); + await collectEndpointAsserter.assertNeitherCollectNorInteractCalled(); + await clickLink("#alloy-link-test"); + await collectEndpointAsserter.assertInteractCalledAndNotCollect(); + const interactRequest = collectEndpointAsserter.getInteractRequest(); + + const expectedXdmWebInteraction = { + name: "Augmented name", + region: "BODY", + type: "other", + URL: "https://alloyio.com/functional-test/valid.html", + linkClicks: { value: 1 }, + }; + + const expectedData = { + __adobe: { + analytics: { + contextData: { + a: { + activitymap: { + link: "Augmented name", + page: "https://alloyio.com/functional-test/testPage.html", + pageIDType: 0, + region: "BODY", + }, + }, + }, + }, + }, + }; + + await assertRequestXdm( + interactRequest, + expectedXdmWebInteraction, + expectedData, + ); +}); + +test("Test C81181: Verify disabling session storage still captures link click data", async () => { + const collectEndpointAsserter = await createCollectEndpointAsserter(); + await preventLinkNavigation(); + const alloy = createAlloyProxy(); + + const testConfig = compose( + orgMainConfigMain, + clickCollectionEnabled, + clickCollectionEventGroupingDisabled, + clickCollectionSessionStorageDisabled, + ); + + await alloy.configure(testConfig); + await addLinksToBody(); + await clickLink("#alloy-link-test"); + await collectEndpointAsserter.assertInteractCalledAndNotCollect(); + const interactRequest = collectEndpointAsserter.getInteractRequest(); + const expectedXdm = { + name: "Test Link", + region: "BODY", + type: "other", + URL: "https://alloyio.com/functional-test/valid.html", + linkClicks: { value: 1 }, + }; + await assertRequestXdm(interactRequest, expectedXdm); +}); diff --git a/packages/browser/test/functional/specs/Data Collector/C81182.js b/packages/browser/test/functional/specs/Data Collector/C81182.js new file mode 100644 index 000000000..b2e831ae4 --- /dev/null +++ b/packages/browser/test/functional/specs/Data Collector/C81182.js @@ -0,0 +1,165 @@ +/* +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, Selector } from "testcafe"; +import createFixture from "../../helpers/createFixture/index.js"; +import addHtmlToBody from "../../helpers/dom/addHtmlToBody.js"; +import { + compose, + orgMainConfigMain, + clickCollectionEnabled, + clickCollectionDisabled, +} from "../../helpers/constants/configParts/index.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; +import preventLinkNavigation from "../../helpers/preventLinkNavigation.js"; +import { TEST_PAGE as TEST_PAGE_URL } from "../../helpers/constants/url.js"; +import createNetworkLogger from "../../helpers/networkLogger/index.js"; + +const networkLogger = createNetworkLogger(); + +createFixture({ + title: + "C81182: Test onBeforeLinkClickSend callback when personalization metric involved", + url: `${TEST_PAGE_URL}?test=C81182`, + requestHooks: [networkLogger.edgeEndpointLogs], +}); + +test.meta({ + ID: "C81182", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +const addLinkToBody = () => { + return addHtmlToBody( + `Link Click that is canceled`, + ); +}; + +const clickLink = async (selector) => { + await t.click(Selector(selector)); +}; + +const expectedExprienceDecisioning = { + propositionEventType: { + interact: 1, + }, + propositions: [ + { + id: "AT:eyJhY3Rpdml0eUlkIjoiMTQ1NDQ4IiwiZXhwZXJpZW5jZUlkIjoiIn0=", + scope: "__view__", + scopeDetails: { + decisionProvider: "TGT", + activity: { + id: "145448", + }, + characteristics: { + eventToken: "VwlBQpRYFcQXcG9jkRhiRA==", + }, + }, + }, + ], +}; + +const assertRequestXdm = async ( + request, + expectedWebInteraction, + expectedData, +) => { + const requestBody = JSON.parse(request.request.body); + const eventXdm = requestBody.events[0].xdm; + const eventData = requestBody.events[0].data; + await t.expect(eventXdm.eventType).eql("decisioning.propositionInteract"); + await t.expect(eventXdm.web.webInteraction).eql(expectedWebInteraction); + await t.expect(eventData).eql(expectedData); + await t + // eslint-disable-next-line no-underscore-dangle + .expect(eventXdm._experience.decisioning) + .eql(expectedExprienceDecisioning); +}; + +test.skip("Test C81182: Verify that onBeforeLinkClickSend removes the link-click details when personalization metric on link", async () => { + await preventLinkNavigation(); + const alloy = createAlloyProxy(); + + const testConfig = compose(orgMainConfigMain, clickCollectionEnabled, { + onBeforeLinkClickSend: (options) => { + const { data } = options; + + data.customField = "test"; + + return false; + }, + }); + await alloy.configure(testConfig); + await alloy.sendEvent({ renderDecisions: true }); + + await clickLink("#alloy-link-test"); + await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(3); + const linkClickRequest = networkLogger.edgeEndpointLogs.requests[2]; + await assertRequestXdm(linkClickRequest, undefined, undefined); +}); + +test.skip("Test C81182: Verify that onBeforeLinkClickSend augments request when personalization metric on link", async () => { + await preventLinkNavigation(); + const alloy = createAlloyProxy(); + + const testConfig = compose(orgMainConfigMain, clickCollectionEnabled, { + onBeforeLinkClickSend: (options) => { + const { xdm, data, clickedElement } = options; + + if (clickedElement.id === "alloy-link-test") { + xdm.web.webInteraction.name = "augmented link name"; + xdm.web.webInteraction.region = "BODY"; + data.customField = "test123"; + return true; + } + + return false; + }, + }); + await alloy.configure(testConfig); + await addLinkToBody(); + await alloy.sendEvent({ renderDecisions: true }); + + await clickLink("#alloy-link-test"); + await clickLink("#canceled-alloy-link-test"); + + const expectedXdmWebInteraction = { + name: "augmented link name", + region: "BODY", + type: "other", + URL: "https://alloyio.com/functional-test/valid.html", + linkClicks: { value: 1 }, + }; + await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(3); + const linkClickRequest = networkLogger.edgeEndpointLogs.requests[2]; + await assertRequestXdm(linkClickRequest, expectedXdmWebInteraction, { + customField: "test123", + }); +}); + +test.skip("Test C81182: Verify that personalization metric is sent when clickCollection is disabled", async () => { + await preventLinkNavigation(); + const alloy = createAlloyProxy(); + + const testConfig = compose(orgMainConfigMain, clickCollectionDisabled); + await alloy.configure(testConfig); + await addLinkToBody(); + await alloy.sendEvent({ renderDecisions: true }); + + await clickLink("#alloy-link-test"); + await clickLink("#canceled-alloy-link-test"); + + await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(3); + const linkClickRequest = networkLogger.edgeEndpointLogs.requests[2]; + await assertRequestXdm(linkClickRequest, undefined, undefined); +}); diff --git a/packages/browser/test/functional/specs/Data Collector/C81183.js b/packages/browser/test/functional/specs/Data Collector/C81183.js new file mode 100644 index 000000000..d2ce463d8 --- /dev/null +++ b/packages/browser/test/functional/specs/Data Collector/C81183.js @@ -0,0 +1,146 @@ +/* +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 addHtmlToBody from "../../helpers/dom/addHtmlToBody.js"; +import { + compose, + orgMainConfigMain, + clickCollectionEnabled, + clickCollectionDisabled, +} from "../../helpers/constants/configParts/index.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; + +const alloyMonitorScript = ` +window.__alloyMonitors = window.__alloyMonitors || []; +window.__alloyMonitors.push({ + onInstanceConfigured: function(data) { + window.___getLinkDetails = data.getLinkDetails; + } + });`; + +createFixture({ + title: "C81181: getLinkDetails monitoring hook function", + monitoringHooksScript: alloyMonitorScript, +}); + +test.meta({ + ID: "C81181", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +const addLinksToBody = () => { + return addHtmlToBody( + `Test Link + Link Click that is canceled`, + ); +}; + +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 C81183: Verify that it returns the object augmented by onBeforeLinkClickSend", async () => { + const alloy = createAlloyProxy(); + + const testConfig = compose(orgMainConfigMain, clickCollectionEnabled, { + onBeforeLinkClickSend: (options) => { + const { xdm, data, clickedElement } = options; + if (clickedElement.id === "cancel-alloy-link-test") { + return false; + } + xdm.web.webInteraction.name = "augmented name"; + data.customField = "test123"; + + return true; + }, + }); + const expectedLinkDetails = { + linkName: "Test Link", + linkRegion: "BODY", + linkType: "other", + linkUrl: "https://alloyio.com/functional-test/valid.html", + pageName: "https://alloyio.com/functional-test/testPage.html", + }; + + await alloy.configure(testConfig); + await addLinksToBody(); + const result = await getLinkDetails("alloy-link-test"); + await t.expect(result).eql(expectedLinkDetails); +}); + +test("Test C81183: Verify that it returns undefined if onBeforeLinkClickSend returns false", async () => { + const alloy = createAlloyProxy(); + + const testConfig = compose(orgMainConfigMain, clickCollectionEnabled, { + onBeforeLinkClickSend: (options) => { + const { xdm, data, clickedElement } = options; + if (clickedElement.id === "cancel-alloy-link-test") { + return false; + } + xdm.web.webInteraction.name = "augmented name"; + data.customField = "test123"; + + return true; + }, + }); + + await alloy.configure(testConfig); + await addLinksToBody(); + const linkDetails = await getLinkDetails("cancel-alloy-link-test"); + await t.wait(10000); + await t.expect(linkDetails).eql({ + linkName: undefined, + linkRegion: undefined, + linkType: undefined, + linkUrl: undefined, + pageName: undefined, + }); +}); + +test("Test C81183: Verify that it returns linkDetails irrespective on clickCollectionEnabled", async () => { + const alloy = createAlloyProxy(); + + const testConfig = compose(orgMainConfigMain, clickCollectionDisabled); + + await alloy.configure(testConfig); + await addLinksToBody(); + const expectedLinkDetails = { + linkName: "Test Link", + linkRegion: "BODY", + linkType: "other", + linkUrl: "https://alloyio.com/functional-test/valid.html", + pageName: "https://alloyio.com/functional-test/testPage.html", + }; + + await t.expect(getLinkDetails("cancel-alloy-link-test")).eql({ + linkName: undefined, + linkRegion: undefined, + linkType: undefined, + linkUrl: undefined, + pageName: undefined, + }); + await t.expect(getLinkDetails("alloy-link-test")).eql(expectedLinkDetails); +}); diff --git a/packages/browser/test/functional/specs/Data Collector/C81184.js b/packages/browser/test/functional/specs/Data Collector/C81184.js new file mode 100644 index 000000000..a45d3986f --- /dev/null +++ b/packages/browser/test/functional/specs/Data Collector/C81184.js @@ -0,0 +1,146 @@ +/* +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. +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/packages/browser/test/functional/specs/Data Collector/C8119.js b/packages/browser/test/functional/specs/Data Collector/C8119.js new file mode 100644 index 000000000..289bc379d --- /dev/null +++ b/packages/browser/test/functional/specs/Data Collector/C8119.js @@ -0,0 +1,55 @@ +/* +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, Selector } from "testcafe"; +import createFixture from "../../helpers/createFixture/index.js"; +import addHtmlToBody from "../../helpers/dom/addHtmlToBody.js"; +import { + compose, + orgMainConfigMain, +} from "../../helpers/constants/configParts/index.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; +import preventLinkNavigation from "../../helpers/preventLinkNavigation.js"; +import createCollectEndpointAsserter from "../../helpers/createCollectEndpointAsserter.js"; + +createFixture({ + title: + "C8119: Does not send event with information about link clicks if disabled.", +}); + +test.meta({ + ID: "C8119", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +const addLinkToBody = () => { + return addHtmlToBody( + `Test Link`, + ); +}; + +const clickLink = async () => { + await t.click(Selector("#alloy-link-test")); +}; + +test("Test C8119: Load page with link. Click link. Verify no event sent.", async () => { + const collectEndpointAsserter = await createCollectEndpointAsserter(); + await preventLinkNavigation(); + const alloy = createAlloyProxy(); + const testConfig = compose(orgMainConfigMain, { + clickCollectionEnabled: false, + }); + await alloy.configure(testConfig); + await addLinkToBody(); + await clickLink(); + await collectEndpointAsserter.assertNeitherCollectNorInteractCalled(); +}); diff --git a/packages/browser/test/functional/specs/Data Collector/C9369211.js b/packages/browser/test/functional/specs/Data Collector/C9369211.js new file mode 100644 index 000000000..a68343b01 --- /dev/null +++ b/packages/browser/test/functional/specs/Data Collector/C9369211.js @@ -0,0 +1,70 @@ +/* +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 } from "testcafe"; +import createNetworkLogger from "../../helpers/networkLogger/index.js"; +import { responseStatus } from "../../helpers/assertions/index.js"; +import createFixture from "../../helpers/createFixture/index.js"; +import { + compose, + orgMainConfigMain, + debugEnabled, +} from "../../helpers/constants/configParts/index.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; +import { TEST_PAGE } from "../../helpers/constants/url.js"; +import createCollectEndpointAsserter from "../../helpers/createCollectEndpointAsserter.js"; + +const networkLogger = createNetworkLogger(); +const config = compose(orgMainConfigMain, debugEnabled); + +createFixture({ + title: "C9369211: sendEvent includes a header for the referer", + requestHooks: [ + networkLogger.edgeEndpointLogs, + networkLogger.edgeCollectEndpointLogs, + ], +}); + +test.meta({ + ID: "C9369211", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +test("Test C9369211: sendEvent includes a header for the referer when calling interact.", async () => { + const alloy = createAlloyProxy(); + await alloy.configure(config); + await alloy.sendEvent({}); + + await responseStatus(networkLogger.edgeEndpointLogs.requests, [200, 207]); + await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(1); + + await t + .expect(networkLogger.edgeEndpointLogs.requests[0].request.headers.referer) + .eql(TEST_PAGE); +}); + +test("Test C9369211: sendEvent includes a header for the referer when calling collect.", async () => { + const collectEndpointAsserter = await createCollectEndpointAsserter(); + + const alloy = createAlloyProxy(); + await alloy.configure(config); + await alloy.sendEvent({}); // establish an identity + await collectEndpointAsserter.reset(); + await alloy.sendEvent({ documentUnloading: true }); + await collectEndpointAsserter.assertCollectCalledAndNotInteract(); + + // TODO: Testcafe no longer captures the request body for sendBeacon requests. + // We could enhance this test to use Assurance to verify the request body. + // await t + // .expect(collectEndpointAsserter.getCollectRequest().request.headers.referer) + // .eql(TEST_PAGE); +}); diff --git a/packages/browser/test/functional/specs/ID Migration/C14394.js b/packages/browser/test/functional/specs/ID Migration/C14394.js new file mode 100644 index 000000000..3e880e1f4 --- /dev/null +++ b/packages/browser/test/functional/specs/ID Migration/C14394.js @@ -0,0 +1,73 @@ +/* +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 } from "testcafe"; +import createNetworkLogger from "../../helpers/networkLogger/index.js"; +import getResponseBody from "../../helpers/networkLogger/getResponseBody.js"; +import { responseStatus } from "../../helpers/assertions/index.js"; +import createFixture from "../../helpers/createFixture/index.js"; +import createResponse from "../../helpers/createResponse.js"; +import { + compose, + orgMainConfigMain, + debugEnabled, + migrationEnabled, +} from "../../helpers/constants/configParts/index.js"; +import setLegacyIdentityCookie from "../../helpers/setLegacyIdentityCookie.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; + +const config = compose(orgMainConfigMain, debugEnabled, migrationEnabled); + +const networkLogger = createNetworkLogger(); + +createFixture({ + title: + "C14394: When ID migration is enabled and no identity cookie is found but legacy identity cookie is found, the ECID will be sent on the request", + requestHooks: [networkLogger.edgeEndpointLogs], +}); + +test.meta({ + ID: "C14394", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +test("Test C14394: When ID migration is enabled and no identity cookie is found but legacy identity cookie is found, the ECID will be sent on the request", async () => { + await setLegacyIdentityCookie(orgMainConfigMain.orgId); + + const alloy = createAlloyProxy(); + await alloy.configure(config); + await alloy.sendEvent({ renderDecisions: true }); + + await responseStatus(networkLogger.edgeEndpointLogs.requests, [200, 207]); + + const request = JSON.parse( + networkLogger.edgeEndpointLogs.requests[0].request.body, + ); + + await t + .expect(request.xdm.identityMap.ECID[0].id) + .eql("16908443662402872073525706953453086963"); + + const response = JSON.parse( + getResponseBody(networkLogger.edgeEndpointLogs.requests[0]), + ); + + const payloads = createResponse({ content: response }).getPayloadsByType( + "identity:result", + ); + + const ecidPayload = payloads.filter( + (payload) => payload.namespace.code === "ECID", + )[0]; + + await t.expect(ecidPayload.id).eql("16908443662402872073525706953453086963"); +}); diff --git a/packages/browser/test/functional/specs/ID Migration/C14399.js b/packages/browser/test/functional/specs/ID Migration/C14399.js new file mode 100644 index 000000000..fe32d5001 --- /dev/null +++ b/packages/browser/test/functional/specs/ID Migration/C14399.js @@ -0,0 +1,83 @@ +/* +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 createNetworkLogger from "../../helpers/networkLogger/index.js"; +import getResponseBody from "../../helpers/networkLogger/getResponseBody.js"; +import { responseStatus } from "../../helpers/assertions/index.js"; +import createFixture from "../../helpers/createFixture/index.js"; +import createResponse from "../../helpers/createResponse.js"; +import { + compose, + orgMainConfigMain, + debugEnabled, + migrationEnabled, +} from "../../helpers/constants/configParts/index.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; + +const config = compose(orgMainConfigMain, debugEnabled, migrationEnabled); + +const networkLogger = createNetworkLogger(); + +createFixture({ + title: + "C14399: When ID migration is enabled and no identity cookie is found but legacy s_ecid cookie is found, the ECID will be sent on the request", + requestHooks: [networkLogger.edgeEndpointLogs], +}); + +test.meta({ + ID: "C14399", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +const setEcidCookie = ClientFunction(() => { + document.cookie = "s_ecid=MCMID%7C16908443662402872073525706953453086963"; +}); + +const getDocumentCookie = ClientFunction(() => document.cookie); + +test("Test C14399: When ID migration is enabled and no identity cookie is found but legacy s_ecid cookie is found, the ECID will be sent on the request", async () => { + await setEcidCookie(); + const alloy = createAlloyProxy(); + await alloy.configure(config); + await alloy.sendEvent({ renderDecisions: true }); + + await responseStatus(networkLogger.edgeEndpointLogs.requests, [200, 207]); + + const request = JSON.parse( + networkLogger.edgeEndpointLogs.requests[0].request.body, + ); + + await t + .expect(request.xdm.identityMap.ECID[0].id) + .eql("16908443662402872073525706953453086963"); + + const response = JSON.parse( + getResponseBody(networkLogger.edgeEndpointLogs.requests[0]), + ); + + const payloads = createResponse({ content: response }).getPayloadsByType( + "identity:result", + ); + + const ecidPayload = payloads.filter( + (payload) => payload.namespace.code === "ECID", + )[0]; + + await t.expect(ecidPayload.id).eql("16908443662402872073525706953453086963"); + + const documentCookie = await getDocumentCookie(); + + await t + .expect(documentCookie) + .contains("s_ecid=MCMID%7C16908443662402872073525706953453086963"); +}); diff --git a/packages/browser/test/functional/specs/ID Migration/C14400.js b/packages/browser/test/functional/specs/ID Migration/C14400.js new file mode 100644 index 000000000..53c8277a5 --- /dev/null +++ b/packages/browser/test/functional/specs/ID Migration/C14400.js @@ -0,0 +1,84 @@ +/* +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 createNetworkLogger from "../../helpers/networkLogger/index.js"; +import getResponseBody from "../../helpers/networkLogger/getResponseBody.js"; +import { responseStatus } from "../../helpers/assertions/index.js"; +import createFixture from "../../helpers/createFixture/index.js"; +import createResponse from "../../helpers/createResponse.js"; +import { ECID as ECID_REGEX } from "../../helpers/constants/regex.js"; +import { + compose, + orgMainConfigMain, + debugEnabled, + migrationDisabled, +} from "../../helpers/constants/configParts/index.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; + +const config = compose(orgMainConfigMain, debugEnabled, migrationDisabled); + +const networkLogger = createNetworkLogger(); + +createFixture({ + title: + "C14400: When ID migration is disabled and no identity cookie is found but legacy s_ecid cookie is found, the ECID should not be sent on the request", + requestHooks: [networkLogger.edgeEndpointLogs], +}); + +test.meta({ + ID: "C14400", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +const setEcidCookie = ClientFunction(() => { + document.cookie = "s_ecid=MCMID%7C16908443662402872073525706953453086963"; +}); + +const getDocumentCookie = ClientFunction(() => document.cookie); + +test("Test C14400: When ID migration is disabled and no identity cookie is found but legacy s_ecid cookie is found, the ECID should not be sent on the request", async () => { + await setEcidCookie(); + const alloy = createAlloyProxy(); + await alloy.configure(config); + await alloy.sendEvent({ renderDecisions: true }); + + await responseStatus(networkLogger.edgeEndpointLogs.requests, [200, 207]); + + const request = JSON.parse( + networkLogger.edgeEndpointLogs.requests[0].request.body, + ); + + await t.expect(request.xdm).eql(undefined); + + const response = JSON.parse( + getResponseBody(networkLogger.edgeEndpointLogs.requests[0]), + ); + + const payloads = createResponse({ content: response }).getPayloadsByType( + "identity:result", + ); + + const ecidPayload = payloads.filter( + (payload) => payload.namespace.code === "ECID", + )[0]; + + await t.expect(ecidPayload.id).match(ECID_REGEX); + + const documentCookie = await getDocumentCookie(); + + await t + .expect(documentCookie) + .notContains( + `AMCV_5BFE274A5F6980A50A495C08%40AdobeOrg=MCMID|${ecidPayload.id}`, + ); +}); diff --git a/packages/browser/test/functional/specs/ID Migration/C14401.js b/packages/browser/test/functional/specs/ID Migration/C14401.js new file mode 100644 index 000000000..aebc29acd --- /dev/null +++ b/packages/browser/test/functional/specs/ID Migration/C14401.js @@ -0,0 +1,71 @@ +/* +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 } from "testcafe"; +import createNetworkLogger from "../../helpers/networkLogger/index.js"; +import getResponseBody from "../../helpers/networkLogger/getResponseBody.js"; +import { responseStatus } from "../../helpers/assertions/index.js"; +import createFixture from "../../helpers/createFixture/index.js"; +import createResponse from "../../helpers/createResponse.js"; +import { ECID as ECID_REGEX } from "../../helpers/constants/regex.js"; +import { + compose, + orgMainConfigMain, + debugEnabled, + migrationDisabled, +} from "../../helpers/constants/configParts/index.js"; +import setLegacyIdentityCookie from "../../helpers/setLegacyIdentityCookie.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; + +const config = compose(orgMainConfigMain, debugEnabled, migrationDisabled); + +const networkLogger = createNetworkLogger(); + +createFixture({ + title: + "C14401: When ID migration is disabled and no identity cookie is found but legacy identity cookie is found, the ECID will not be sent on the request", + requestHooks: [networkLogger.edgeEndpointLogs], +}); + +test.meta({ + ID: "C14401", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +test("Test C14401: When ID migration is disabled and no identity cookie is found but legacy identity cookie is found, the ECID will not be sent on the request", async () => { + await setLegacyIdentityCookie(orgMainConfigMain.orgId); + const alloy = createAlloyProxy(); + await alloy.configure(config); + await alloy.sendEvent({ renderDecisions: true }); + + await responseStatus(networkLogger.edgeEndpointLogs.requests, [200, 207]); + + const request = JSON.parse( + networkLogger.edgeEndpointLogs.requests[0].request.body, + ); + + await t.expect(request.xdm).eql(undefined); + + const response = JSON.parse( + getResponseBody(networkLogger.edgeEndpointLogs.requests[0]), + ); + + const payloads = createResponse({ content: response }).getPayloadsByType( + "identity:result", + ); + + const ecidPayload = payloads.filter( + (payload) => payload.namespace.code === "ECID", + )[0]; + + await t.expect(ecidPayload.id).match(ECID_REGEX); +}); diff --git a/packages/browser/test/functional/specs/ID Migration/C14402.js b/packages/browser/test/functional/specs/ID Migration/C14402.js new file mode 100644 index 000000000..ee0c497f4 --- /dev/null +++ b/packages/browser/test/functional/specs/ID Migration/C14402.js @@ -0,0 +1,93 @@ +/* +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 createNetworkLogger from "../../helpers/networkLogger/index.js"; +import getResponseBody from "../../helpers/networkLogger/getResponseBody.js"; +import { responseStatus } from "../../helpers/assertions/index.js"; +import createFixture from "../../helpers/createFixture/index.js"; +import createResponse from "../../helpers/createResponse.js"; +import { ECID as ECID_REGEX } from "../../helpers/constants/regex.js"; +import { + compose, + orgMainConfigMain, + debugEnabled, + migrationEnabled, +} from "../../helpers/constants/configParts/index.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; +import { + LEGACY_IDENTITY_COOKIE_NAME, + LEGACY_IDENTITY_COOKIE_UNESCAPED_NAME, +} from "../../helpers/constants/cookies.js"; +import createConsoleLogger from "../../helpers/consoleLogger/index.js"; + +const config = compose(orgMainConfigMain, debugEnabled, migrationEnabled); + +const networkLogger = createNetworkLogger(); + +createFixture({ + title: + "C14402: When ID migration is enabled and no legacy AMCV cookie is found, an AMCV cookie should be created", + requestHooks: [networkLogger.edgeEndpointLogs], +}); + +test.meta({ + ID: "C14402", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +const getDocumentCookie = ClientFunction(() => document.cookie); + +test("Test C14402: When ID migration is enabled and no legacy AMCV cookie is found, an AMCV cookie should be created", async () => { + const logger = await createConsoleLogger(); + const alloy = createAlloyProxy(); + await alloy.configure(config); + await logger.reset(); + await alloy.sendEvent({ renderDecisions: true }); + + await responseStatus(networkLogger.edgeEndpointLogs.requests, [200, 207]); + + const response = JSON.parse( + getResponseBody(networkLogger.edgeEndpointLogs.requests[0]), + ); + + const payloads = createResponse({ content: response }).getPayloadsByType( + "identity:result", + ); + + const ecidPayload = payloads.filter( + (payload) => payload.namespace.code === "ECID", + )[0]; + + await t.expect(ecidPayload.id).match(ECID_REGEX); + + const documentCookie = await getDocumentCookie(); + + await t + .expect(documentCookie) + .contains(`${LEGACY_IDENTITY_COOKIE_NAME}=MCMID|${ecidPayload.id}`); + + const logs = await logger.info.getMessagesSinceReset(); + const setCookieAttributes = logs + .filter( + (message) => message.length === 3 && message[1] === "Setting cookie", + ) + .map((message) => message[2]) + .filter( + (cookieSettings) => + cookieSettings.name === LEGACY_IDENTITY_COOKIE_UNESCAPED_NAME, + ); + + await t.expect(setCookieAttributes.length).eql(1); + await t.expect(setCookieAttributes[0].sameSite).eql("none"); + await t.expect(setCookieAttributes[0].secure).eql(true); +}); diff --git a/packages/browser/test/functional/specs/ID Migration/C14403.js b/packages/browser/test/functional/specs/ID Migration/C14403.js new file mode 100644 index 000000000..76e62c813 --- /dev/null +++ b/packages/browser/test/functional/specs/ID Migration/C14403.js @@ -0,0 +1,73 @@ +/* +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 createNetworkLogger from "../../helpers/networkLogger/index.js"; +import getResponseBody from "../../helpers/networkLogger/getResponseBody.js"; +import { responseStatus } from "../../helpers/assertions/index.js"; +import createFixture from "../../helpers/createFixture/index.js"; +import createResponse from "../../helpers/createResponse.js"; +import { ECID as ECID_REGEX } from "../../helpers/constants/regex.js"; +import { + compose, + orgMainConfigMain, + debugEnabled, + migrationDisabled, +} from "../../helpers/constants/configParts/index.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; + +const config = compose(orgMainConfigMain, debugEnabled, migrationDisabled); + +const networkLogger = createNetworkLogger(); + +createFixture({ + title: + "C14403: When ID migration is disabled and no legacy AMCV cookie is found, no AMCV cookie should be created", + requestHooks: [networkLogger.edgeEndpointLogs], +}); + +test.meta({ + ID: "C14403", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +const getDocumentCookie = ClientFunction(() => document.cookie); + +test("Test C14403: When ID migration is disabled and no legacy AMCV cookie is found, no AMCV cookie should be created", async () => { + const alloy = createAlloyProxy(); + await alloy.configure(config); + await alloy.sendEvent({ renderDecisions: true }); + + await responseStatus(networkLogger.edgeEndpointLogs.requests, [200, 207]); + + const response = JSON.parse( + getResponseBody(networkLogger.edgeEndpointLogs.requests[0]), + ); + + const payloads = createResponse({ content: response }).getPayloadsByType( + "identity:result", + ); + + const ecidPayload = payloads.filter( + (payload) => payload.namespace.code === "ECID", + )[0]; + + await t.expect(ecidPayload.id).match(ECID_REGEX); + + const documentCookie = await getDocumentCookie(); + + await t + .expect(documentCookie) + .notContains( + `AMCV_5BFE274A5F6980A50A495C08%40AdobeOrg=MCMID|${ecidPayload.id}`, + ); +}); diff --git a/packages/browser/test/functional/specs/ID Migration/C5752639.js b/packages/browser/test/functional/specs/ID Migration/C5752639.js new file mode 100644 index 000000000..9021c6bc0 --- /dev/null +++ b/packages/browser/test/functional/specs/ID Migration/C5752639.js @@ -0,0 +1,73 @@ +/* +Copyright 2022 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 { + compose, + orgMainConfigMain, + debugEnabled, + migrationEnabled, +} from "../../helpers/constants/configParts/index.js"; +import createNetworkLogger from "../../helpers/networkLogger/index.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; +import reloadPage from "../../helpers/reloadPage.js"; +import createRandomEcid from "../../helpers/createRandomEcid.js"; +import createAdobeMC from "../../helpers/createAdobeMC.js"; +import getReturnedEcid from "../../helpers/networkLogger/getReturnedEcid.js"; +import setLegacyIdentityCookie from "../../helpers/setLegacyIdentityCookie.js"; +import { LEGACY_IDENTITY_COOKIE_NAME } from "../../helpers/constants/cookies.js"; + +const config = compose(orgMainConfigMain, debugEnabled, migrationEnabled); + +const networkLogger = createNetworkLogger(); + +const id = createRandomEcid(); +const adobemc = createAdobeMC({ id }); + +createFixture({ + title: + "C5752639: Identity can be changed via the adobe_mc query string parameter when id_migration is enabled", + requestHooks: [networkLogger.edgeEndpointLogs], +}); + +test.meta({ + ID: "C5752639", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +const getDocumentCookie = ClientFunction(() => document.cookie); + +test("C5752639: Identity can be changed via the adobe_mc query string parameter when id_migration is enabled", async () => { + setLegacyIdentityCookie(); + + const alloy = createAlloyProxy(); + await alloy.configure(config); + await alloy.sendEvent({}); + + await reloadPage(`adobe_mc=${adobemc}`); + await alloy.configure(config); + await alloy.sendEvent({}); + + await reloadPage(""); + await alloy.configure(config); + await alloy.sendEvent({}); + + const documentCookie = await getDocumentCookie(); + await t + .expect(documentCookie) + .contains(`${LEGACY_IDENTITY_COOKIE_NAME}=MCMID|${id}`); + + const ecid = getReturnedEcid(networkLogger.edgeEndpointLogs.requests[2]); + await t.expect(ecid).eql(id); +}); diff --git a/packages/browser/test/functional/specs/Identity/C10922.js b/packages/browser/test/functional/specs/Identity/C10922.js new file mode 100644 index 000000000..4644cf461 --- /dev/null +++ b/packages/browser/test/functional/specs/Identity/C10922.js @@ -0,0 +1,157 @@ +/* +Copyright 2020 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 } from "testcafe"; +import createNetworkLogger from "../../helpers/networkLogger/index.js"; +import createFixture from "../../helpers/createFixture/index.js"; +import { + compose, + edgeDomainThirdParty, + edgeDomainFirstParty, + orgMainConfigMain, + thirdPartyCookiesDisabled, + thirdPartyCookiesEnabled, + migrationEnabled, + migrationDisabled, +} from "../../helpers/constants/configParts/index.js"; +import reloadPage from "../../helpers/reloadPage.js"; +import setLegacyIdentityCookie from "../../helpers/setLegacyIdentityCookie.js"; +import areThirdPartyCookiesSupported from "../../helpers/areThirdPartyCookiesSupported.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; + +const networkLogger = createNetworkLogger(); + +const demdexHostRegex = /\.demdex\.net/; + +const getHostForFirstRequest = () => { + const firstRequest = networkLogger.edgeInteractEndpointLogs.requests[0]; + return firstRequest.request.url; +}; + +const assertRequestWentToDemdex = async () => { + await t.expect(getHostForFirstRequest()).match(demdexHostRegex); +}; + +const assertRequestDidNotGoToDemdex = async () => { + await t.expect(getHostForFirstRequest()).notMatch(demdexHostRegex); +}; + +createFixture({ + title: "C10922 - demdex usage", + requestHooks: [networkLogger.edgeInteractEndpointLogs], +}); + +fixture.beforeEach(async () => { + await setLegacyIdentityCookie(orgMainConfigMain.orgId); +}); + +test.meta({ + ID: "C10922", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +const permutationsUsingDemdex = [ + { + description: "third-party cookies enabled", + config: compose( + orgMainConfigMain, + thirdPartyCookiesEnabled, + edgeDomainThirdParty, + migrationDisabled, + ), + }, + { + description: "third-party cookies enabled and first-party edge domain", + config: compose( + orgMainConfigMain, + thirdPartyCookiesEnabled, + edgeDomainFirstParty, + migrationDisabled, + ), + }, + { + // If we have a identity to migrate, we still want to hit demdex because + // demdex will use our ECID to set the third-party cookie if the third-party + // cookie isn't already set, which provides for better cross-domain + // identification for future requests. + description: + "third-party cookies enabled and migration enabled with existing legacy identity cookie", + config: compose( + orgMainConfigMain, + thirdPartyCookiesEnabled, + edgeDomainThirdParty, + migrationEnabled, + ), + }, +]; + +permutationsUsingDemdex.forEach((permutation) => { + test(`C10922 - demdex is used for first request when configured with ${permutation.description} and browser supports third-party cookies by default`, async () => { + const alloy = createAlloyProxy(); + await alloy.configure(permutation.config); + await alloy.sendEvent(); + + if (areThirdPartyCookiesSupported()) { + await assertRequestWentToDemdex(); + } else { + await assertRequestDidNotGoToDemdex(); + } + await networkLogger.clearLogs(); + await reloadPage(); + await alloy.configure(permutation.config); + await alloy.sendEvent(); + // The request should not have gone to the third-party domain + // because we already have an identity cookie. + await assertRequestDidNotGoToDemdex(); + }); +}); + +const permutationsNotUsingDemdex = [ + { + description: "third-party cookies disabled", + config: compose( + orgMainConfigMain, + thirdPartyCookiesDisabled, + edgeDomainThirdParty, + migrationDisabled, + ), + }, + { + description: "third-party cookies disabled and first-party edge domain", + config: compose( + orgMainConfigMain, + thirdPartyCookiesDisabled, + edgeDomainFirstParty, + migrationDisabled, + ), + }, + { + description: + "third-party cookies disabled and migration enabled with existing legacy identity cookie", + config: compose( + orgMainConfigMain, + thirdPartyCookiesDisabled, + edgeDomainFirstParty, + migrationEnabled, + ), + }, +]; + +permutationsNotUsingDemdex.forEach((permutation) => { + test(`C10922 - demdex is not used when configured with ${permutation.description}`, async () => { + const alloy = createAlloyProxy(); + await alloy.configure(permutation.config); + await alloy.sendEvent(); + await assertRequestDidNotGoToDemdex(); + }); +}); diff --git a/packages/browser/test/functional/specs/Identity/C14699834.js b/packages/browser/test/functional/specs/Identity/C14699834.js new file mode 100644 index 000000000..2b9a7e9cd --- /dev/null +++ b/packages/browser/test/functional/specs/Identity/C14699834.js @@ -0,0 +1,119 @@ +/* +Copyright 2022 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 } from "testcafe"; +import { + compose, + orgMainConfigMain, + thirdPartyCookiesDisabled, + debugEnabled, + edgeDomainFirstParty, +} from "../../helpers/constants/configParts/index.js"; +import { TEST_PAGE } from "../../helpers/constants/url.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; +import createFixture from "../../helpers/createFixture/index.js"; +import cookies from "../../helpers/cookies.js"; +import { MAIN_IDENTITY_COOKIE_NAME } from "../../helpers/constants/cookies.js"; +import { CONSENT_IN } from "../../helpers/constants/consent.js"; + +createFixture({ + url: TEST_PAGE, + title: "C14699834: Identity is still established if first request fails", +}); + +test.meta({ + ID: "C9999999", + SEVERTIY: "P0", + TEST_RUN: "Regression", +}); + +const config = compose( + orgMainConfigMain, + thirdPartyCookiesDisabled, + debugEnabled, + edgeDomainFirstParty, +); + +test("C14699834: Identity is still established if the first send event fails", async () => { + const alloy = createAlloyProxy(); + await alloy.configure(config); + const errorMessage = await alloy.sendEventErrorMessage({ + xdm: { + identityMap: { + ECID: [ + { + id: "INVALID_ID", + }, + ], + }, + }, + }); + await t.expect(await errorMessage).contains("INVALID_ID"); + // make sure we don't have an ECID + const identityCookieValue1 = await cookies.get(MAIN_IDENTITY_COOKIE_NAME); + await t + .expect(identityCookieValue1) + .notOk("Identity cookie found prematurely."); + + await alloy.sendEvent({}); + + // make sure we have an ecid + const identityCookieValue2 = await cookies.get(MAIN_IDENTITY_COOKIE_NAME); + await t.expect(identityCookieValue2).ok("No identity cookie found."); +}); + +test("C14699834: Identity is still established if the first set consent fails", async () => { + const alloy = createAlloyProxy(); + await alloy.configure(config); + const errorMessage = await alloy.setConsentErrorMessage({ + identityMap: { + ECID: [ + { + id: "INVALID_ID", + }, + ], + }, + ...CONSENT_IN, + }); + await t.expect(await errorMessage).contains("INVALID_ID"); + // make sure we don't have an ECID + const identityCookieValue1 = await cookies.get(MAIN_IDENTITY_COOKIE_NAME); + await t + .expect(identityCookieValue1) + .notOk("Identity cookie found prematurely."); + + await alloy.setConsent(CONSENT_IN); + + // make sure we have an ecid + const identityCookieValue2 = await cookies.get(MAIN_IDENTITY_COOKIE_NAME); + await t.expect(identityCookieValue2).ok("No identity cookie found."); +}); + +test("C14699834: Identity is still established if the first get identity fails", async () => { + const alloy = createAlloyProxy(); + await alloy.configure(config); + const errorMessage = await alloy.getIdentityErrorMessage({ + edgeConfigOverrides: { myinvalidoverride: "myvalue" }, + }); + await t.expect(await errorMessage).contains("myinvalidoverride"); + // make sure we don't have an ECID + const identityCookieValue1 = await cookies.get(MAIN_IDENTITY_COOKIE_NAME); + await t + .expect(identityCookieValue1) + .notOk("Identity cookie found prematurely."); + + await alloy.getIdentity(); + + // make sure we have an ecid + const identityCookieValue2 = await cookies.get(MAIN_IDENTITY_COOKIE_NAME); + await t.expect(identityCookieValue2).ok("No identity cookie found."); +}); diff --git a/packages/browser/test/functional/specs/Identity/C15325238.js b/packages/browser/test/functional/specs/Identity/C15325238.js new file mode 100644 index 000000000..62539231c --- /dev/null +++ b/packages/browser/test/functional/specs/Identity/C15325238.js @@ -0,0 +1,75 @@ +/* +Copyright 2022 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 } from "testcafe"; +import createFixture from "../../helpers/createFixture/index.js"; +import { SECONDARY_TEST_PAGE, TEST_PAGE } from "../../helpers/constants/url.js"; +import { + compose, + orgMainConfigMain, + debugEnabled, + thirdPartyCookiesDisabled, +} from "../../helpers/constants/configParts/index.js"; +import createNetworkLogger from "../../helpers/networkLogger/index.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; +import getReturnedEcid from "../../helpers/networkLogger/getReturnedEcid.js"; + +// We disable third party cookies so that the domains don't share identities +// through the demdex cookies. +const config = compose( + orgMainConfigMain, + debugEnabled, + thirdPartyCookiesDisabled, +); + +const networkLogger = createNetworkLogger(); + +createFixture({ + title: + "C15325238: When there are multiple adobe_mc parameters, the last one is used.", + requestHooks: [networkLogger.edgeEndpointLogs], +}); + +test.meta({ + ID: "C15325238", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +test("C15325238: When there are multiple adobe_mc parameters, the last one is used.", async () => { + const alloy = createAlloyProxy(); + await alloy.configure(config); + await alloy.sendEvent({}); + const { url: newUrl1 } = await alloy.appendIdentityToUrl({ + url: TEST_PAGE, + }); + + await t.navigateTo(SECONDARY_TEST_PAGE); + await alloy.configure(config); + await alloy.sendEvent({}); + + const { url: newUrl2 } = await alloy.appendIdentityToUrl({ + url: newUrl1, + }); + + await t.navigateTo(newUrl2); + await alloy.configure(config); + await alloy.sendEvent({}); + + const [ecid1, ecid2, ecid3] = + networkLogger.edgeEndpointLogs.requests.map(getReturnedEcid); + await t.expect(ecid1).notEql(ecid2); + await t.expect(ecid2).eql(ecid3); + + const { identity } = await alloy.getIdentity(); + await t.expect(identity.ECID).eql(ecid2); +}); diff --git a/packages/browser/test/functional/specs/Identity/C1703722.js b/packages/browser/test/functional/specs/Identity/C1703722.js new file mode 100644 index 000000000..140bffdd4 --- /dev/null +++ b/packages/browser/test/functional/specs/Identity/C1703722.js @@ -0,0 +1,50 @@ +/* +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 } from "testcafe"; +import createFixture from "../../helpers/createFixture/index.js"; +import cookies from "../../helpers/cookies.js"; +import { + compose, + orgMainConfigMain, + debugEnabled, +} from "../../helpers/constants/configParts/index.js"; +import { MAIN_IDENTITY_COOKIE_NAME } from "../../helpers/constants/cookies.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; +import createNetworkLogger from "../../helpers/networkLogger/index.js"; + +const debugEnabledConfig = compose(orgMainConfigMain, debugEnabled); + +const networkLogger = createNetworkLogger(); + +createFixture({ + title: "C1703722: getIdentity works when first command after configure", + requestHooks: [networkLogger.acquireEndpointLogs], +}); + +test.meta({ + ID: "C1703772", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +test("C1703722: getIdentity works when first command after configure", async () => { + const alloy = createAlloyProxy(); + await alloy.configure(debugEnabledConfig); + // this should get an ECID + const identityResponse = await alloy.getIdentity(); + + await t.expect(networkLogger.acquireEndpointLogs.requests.length).eql(1); + const identityCookieValue = await cookies.get(MAIN_IDENTITY_COOKIE_NAME); + await t.expect(identityCookieValue).ok("No identity cookie set."); + await t.expect(identityResponse.identity).ok("No ecid returned"); + await t.expect(identityResponse.edge.regionId).gt(0); +}); diff --git a/packages/browser/test/functional/specs/Identity/C1703723.js b/packages/browser/test/functional/specs/Identity/C1703723.js new file mode 100644 index 000000000..6a7ff3e15 --- /dev/null +++ b/packages/browser/test/functional/specs/Identity/C1703723.js @@ -0,0 +1,52 @@ +/* +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 } from "testcafe"; +import createFixture from "../../helpers/createFixture/index.js"; +import cookies from "../../helpers/cookies.js"; +import { + compose, + orgMainConfigMain, + debugEnabled, +} from "../../helpers/constants/configParts/index.js"; +import { MAIN_IDENTITY_COOKIE_NAME } from "../../helpers/constants/cookies.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; +import createNetworkLogger from "../../helpers/networkLogger/index.js"; + +const debugEnabledConfig = compose(orgMainConfigMain, debugEnabled); + +const networkLogger = createNetworkLogger(); + +createFixture({ + title: + "C1703723: getIdentity uses cached values when interact already called", + requestHooks: [networkLogger.acquireEndpointLogs], +}); + +test.meta({ + ID: "C1703773", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +test("C1703723: getIdentity uses cached values when interact already called", async () => { + const alloy = createAlloyProxy(); + await alloy.configure(debugEnabledConfig); + // this should get an ECID + await alloy.sendEvent(); + const identityResponse = await alloy.getIdentity(); + + await t.expect(networkLogger.acquireEndpointLogs.requests.length).eql(0); + const identityCookieValue = await cookies.get(MAIN_IDENTITY_COOKIE_NAME); + await t.expect(identityCookieValue).ok("No identity cookie set."); + await t.expect(identityResponse.identity).ok("No ecid returned"); + await t.expect(identityResponse.edge.regionId).gt(0); +}); diff --git a/packages/browser/test/functional/specs/Identity/C19160486.js b/packages/browser/test/functional/specs/Identity/C19160486.js new file mode 100644 index 000000000..a5ce20b95 --- /dev/null +++ b/packages/browser/test/functional/specs/Identity/C19160486.js @@ -0,0 +1,176 @@ +/* +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 } from "testcafe"; +import createFixture from "../../helpers/createFixture/index.js"; +import { + compose, + orgMainConfigMain, + debugEnabled, + thirdPartyCookiesEnabled, + thirdPartyCookiesDisabled, +} from "../../helpers/constants/configParts/index.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; +import createNetworkLogger from "../../helpers/networkLogger/index.js"; +import areThirdPartyCookiesSupported from "../../helpers/areThirdPartyCookiesSupported.js"; +import { SECONDARY_TEST_PAGE } from "../../helpers/constants/url.js"; +import reloadPage from "../../helpers/reloadPage.js"; + +const thirdPartyCookiesEnabledConfig = compose( + orgMainConfigMain, + debugEnabled, + thirdPartyCookiesEnabled, +); +const thirdPartyCookiesDisabledConfig = compose( + orgMainConfigMain, + debugEnabled, + thirdPartyCookiesDisabled, +); + +const networkLogger = createNetworkLogger(); + +createFixture({ + title: "C19160486: The CORE identity is returned correctly from getIdentity", + requestHooks: [ + networkLogger.edgeEndpointLogs, + networkLogger.acquireEndpointLogs, + ], +}); + +test.meta({ + ID: "C19160486", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +test("C19160486: CORE identity is the same across domains when called first", async () => { + const alloy = createAlloyProxy(); + await alloy.configure(thirdPartyCookiesEnabledConfig); + const { + identity: { ECID: ecid1, CORE: core1 }, + } = await alloy.getIdentity({ namespaces: ["ECID", "CORE"] }); + await t.navigateTo(SECONDARY_TEST_PAGE); + + await alloy.configure(thirdPartyCookiesEnabledConfig); + const { + identity: { ECID: ecid2, CORE: core2 }, + } = await alloy.getIdentity({ namespaces: ["ECID", "CORE"] }); + + if (areThirdPartyCookiesSupported()) { + // ecids are the same because the same orgId is used to go from CORE -> ECID + await t.expect(ecid1).eql(ecid2); + await t.expect(core1).eql(core2); + await t.expect(ecid1).notEql(core1); + } else { + // ecids are different because third party cookies are not written + await t.expect(ecid1).notEql(ecid2); + // CORE identity is null because Experience Edge only creates it when called on demdex domain + // which only happens on Chrome browsers. + await t.expect(core1).eql(null); + await t.expect(core2).eql(null); + } +}); + +test("C19160486: CORE identity is the same across domains when called after sendEvent", async () => { + const alloy = createAlloyProxy(); + await alloy.configure(thirdPartyCookiesEnabledConfig); + await alloy.sendEvent(); + const { + identity: { ECID: ecid1, CORE: core1 }, + } = await alloy.getIdentity({ namespaces: ["ECID", "CORE"] }); + await t.expect(networkLogger.acquireEndpointLogs.requests.length).eql(0); + await t.navigateTo(SECONDARY_TEST_PAGE); + + await alloy.configure(thirdPartyCookiesEnabledConfig); + await alloy.sendEvent(); + const { + identity: { ECID: ecid2, CORE: core2 }, + } = await alloy.getIdentity({ namespaces: ["ECID", "CORE"] }); + await t.expect(networkLogger.acquireEndpointLogs.requests.length).eql(0); + + if (areThirdPartyCookiesSupported()) { + // ecids are the same because the same orgId is used to go from CORE -> ECID + await t.expect(ecid1).eql(ecid2); + await t.expect(core1).eql(core2); + await t.expect(ecid1).notEql(core1); + } else { + // ecids are different because third party cookies are not written + await t.expect(ecid1).notEql(ecid2); + // CORE identity is null because Experience Edge only creates it when called on demdex domain + // which only happens on Chrome browsers. + await t.expect(core1).eql(null); + await t.expect(core2).eql(null); + } +}); + +test("C19160486: CORE identity is not requested when third party cookies are disabled", async () => { + const alloy = createAlloyProxy(); + await alloy.configure(thirdPartyCookiesDisabledConfig); + await alloy.sendEvent(); + await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(1); + await t.expect(networkLogger.edgeEndpointLogs.count(() => true)).eql(1); + const requestBody = JSON.parse( + networkLogger.edgeEndpointLogs.requests[0].request.body, + ); + await t.expect(requestBody.query.identity.fetch).eql(["ECID"]); +}); + +test("C19160486: CORE identity cannot be requested from getIdentity when third party cookies are disabled", async () => { + const alloy = createAlloyProxy(); + await alloy.configure(thirdPartyCookiesDisabledConfig); + const errorMessage = await alloy.getIdentityErrorMessage({ + namespaces: ["CORE"], + }); + await t + .expect(errorMessage) + .contains( + "The CORE namespace cannot be requested when third-party cookies are disabled", + ); +}); + +test("C19160486: Requesting CORE identity and ECID can be done separately", async () => { + const alloy = createAlloyProxy(); + await alloy.configure(thirdPartyCookiesEnabledConfig); + const { + identity: { ECID: ecid }, + } = await alloy.getIdentity({ namespaces: ["ECID"] }); + await t.expect(ecid).ok(); + const { + identity: { CORE: core }, + } = await alloy.getIdentity({ namespaces: ["CORE"] }); + if (areThirdPartyCookiesSupported()) { + await t.expect(core).ok(); + } else { + await t.expect(core).eql(null); + } +}); + +test("The CORE identity is returned correctly, even when the ECID is read from a cookie", async () => { + const alloy = createAlloyProxy(); + await alloy.configure(thirdPartyCookiesEnabledConfig); + + const { + identity: { ECID: networkEcid, CORE: networkCore }, + } = await alloy.getIdentity({ namespaces: ["ECID", "CORE"] }); + await t.expect(networkEcid).ok(); + await t.expect(networkCore).ok(); + + networkLogger.clearLogs(); + await reloadPage(); + + await alloy.configure(thirdPartyCookiesEnabledConfig); + const { + identity: { ECID: cookieEcid, CORE: newCore }, + } = await alloy.getIdentity({ namespaces: ["ECID", "CORE"] }); + + await t.expect(cookieEcid).eql(networkEcid); + await t.expect(newCore).ok(); +}); diff --git a/packages/browser/test/functional/specs/Identity/C21636436.js b/packages/browser/test/functional/specs/Identity/C21636436.js new file mode 100644 index 000000000..45e9bcd9a --- /dev/null +++ b/packages/browser/test/functional/specs/Identity/C21636436.js @@ -0,0 +1,72 @@ +/** + * Copyright 2025 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 } from "testcafe"; +import createNetworkLogger from "../../helpers/networkLogger/index.js"; +import createFixture from "../../helpers/createFixture/index.js"; +import { + compose, + orgMainConfigMain, + debugEnabled, +} from "../../helpers/constants/configParts/index.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; +import createCollectEndpointAsserter from "../../helpers/createCollectEndpointAsserter.js"; + +const networkLogger = createNetworkLogger(); +const config = compose(orgMainConfigMain, debugEnabled); + +createFixture({ + title: "C21636436: Get Identity after Collect Call", + requestHooks: [networkLogger.acquireEndpointLogs], +}); +test.meta({ + ID: "C21636436", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +test("Preserves ECID after sendEvent call with collect beacon", async () => { + const collectEndpointAsserter = await createCollectEndpointAsserter(); + const alloy = createAlloyProxy(); + await alloy.configure(config); + + await alloy.sendEvent(); + + await collectEndpointAsserter.reset(); + + const initialIdentity = await alloy.getIdentity({ + namespaces: ["ECID"], + }); + + await t + .expect(initialIdentity.identity.ECID) + .ok("No ECID in initial response"); + + const initialEcid = initialIdentity.identity.ECID; + + await alloy.sendEvent({ + documentUnloading: true, + xdm: { + eventType: "test-event", + }, + }); + + await collectEndpointAsserter.assertCollectCalledAndNotInteract(); + + const subsequentIdentity = await alloy.getIdentity({ + namespaces: ["ECID"], + }); + + await t + .expect(subsequentIdentity.identity.ECID) + .eql(initialEcid, "ECID was not preserved after collect call"); +}); diff --git a/packages/browser/test/functional/specs/Identity/C21636437.js b/packages/browser/test/functional/specs/Identity/C21636437.js new file mode 100644 index 000000000..e10f69d56 --- /dev/null +++ b/packages/browser/test/functional/specs/Identity/C21636437.js @@ -0,0 +1,60 @@ +/* +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 { t } from "testcafe"; +import createNetworkLogger from "../../helpers/networkLogger/index.js"; +import createFixture from "../../helpers/createFixture/index.js"; +import { + compose, + orgMainConfigMain, + thirdPartyCookiesEnabled, +} from "../../helpers/constants/configParts/index.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; +import demdexBlockerMock from "../../helpers/requestHooks/demdexBlockerMock.js"; + +const networkLogger = createNetworkLogger(); +const config = compose(orgMainConfigMain, thirdPartyCookiesEnabled); + +createFixture({ + title: "C21636437: Demdex Fallback Behavior", + requestHooks: [networkLogger.edgeEndpointLogs, demdexBlockerMock], +}); + +test.meta({ + ID: "C21636437", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +test("Continues collecting data when demdex is blocked", async () => { + const alloy = createAlloyProxy(); + + await alloy.configure(config); + await alloy.sendEvent(); + + // Get all requests + const requests = networkLogger.edgeEndpointLogs.requests; + + // Find the successful request (should be the last one) + const successfulRequest = requests[requests.length - 1]; + + // Verify the successful request + await t.expect(successfulRequest.request.url).notContains("demdex.net"); + await t.expect(successfulRequest.request.url).contains(config.edgeDomain); + await t.expect(successfulRequest.response.statusCode).eql(200); + + // Verify at least one request was successful + const successfulRequests = requests.filter( + (r) => + !r.request.url.includes("demdex.net") && r.response.statusCode === 200, + ); + await t.expect(successfulRequests.length).gte(1); +}); diff --git a/packages/browser/test/functional/specs/Identity/C21636438.js b/packages/browser/test/functional/specs/Identity/C21636438.js new file mode 100644 index 000000000..112e1a4f5 --- /dev/null +++ b/packages/browser/test/functional/specs/Identity/C21636438.js @@ -0,0 +1,118 @@ +/* +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 { t } from "testcafe"; +import createNetworkLogger from "../../helpers/networkLogger/index.js"; +import createFixture from "../../helpers/createFixture/index.js"; +import { + compose, + orgMainConfigMain, + debugEnabled, +} from "../../helpers/constants/configParts/index.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; +import reloadPage from "../../helpers/reloadPage.js"; + +const networkLogger = createNetworkLogger(); +const config = compose(orgMainConfigMain, debugEnabled); + +createFixture({ + title: "C21636438: Decode the kndctr_ORGID_Identity cookie", + requestHooks: [networkLogger.acquireEndpointLogs], +}); + +test.meta({ + ID: "C21636438", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +test("Extracts information from kndctr cookie", async () => { + const alloy = createAlloyProxy(); + await alloy.configure(config); + + const { + identity: { ECID: networkEcid }, + } = await alloy.getIdentity(); + await t.expect(networkEcid).ok(); + await t.expect(networkLogger.acquireEndpointLogs.requests.length).eql(1); + + networkLogger.clearLogs(); + await reloadPage(); + + await alloy.configure(config); + const { + identity: { ECID: cookieEcid }, + } = await alloy.getIdentity(); + await t.expect(cookieEcid).eql(networkEcid); + await t.expect(networkLogger.acquireEndpointLogs.requests.length).eql(0); +}); + +test("Gracefully falls back to a network request if the cookie is not base64 encoded", async () => { + const alloy = createAlloyProxy(); + await alloy.configure(config); + // Establish the cookie + const { + identity: { ECID: networkEcid }, + } = await alloy.getIdentity(); + await t.expect(networkEcid).ok(); + await t.expect(networkLogger.acquireEndpointLogs.requests.length).eql(1); + // Change the cookie value to be gibberish + const orgId = config.orgId; + const cookieName = `kndctr_${orgId.replace("@", "_")}_identity`; + const cookieValue = "gibberish"; + /** @type { { name: string, value: string, domain: string }[] } */ + const [currentCookie] = await t.getCookies(cookieName); + await t.expect(currentCookie).ok(); + await t.setCookies({ ...currentCookie, value: cookieValue }); + + // Reload the page + networkLogger.clearLogs(); + await reloadPage(); + await alloy.configure(config); + + // Request the identity and ensure a network request was made + const { + identity: { ECID: cookieEcid }, + } = await alloy.getIdentity(); + await t.expect(networkLogger.acquireEndpointLogs.requests.length).eql(1); + await t.expect(cookieEcid).notEql(networkEcid); +}); + +test("Gracefully falls back to a network request if the cookie is base64 decoded but not a valid protobuf", async () => { + const alloy = createAlloyProxy(); + await alloy.configure(config); + // Establish the cookie + const { + identity: { ECID: networkEcid }, + } = await alloy.getIdentity(); + await t.expect(networkEcid).ok(); + await t.expect(networkLogger.acquireEndpointLogs.requests.length).eql(1); + // Change the cookie value to be gibberish + const orgId = config.orgId; + const cookieName = `kndctr_${orgId.replace("@", "_")}_identity`; + const cookieValue = Buffer.from([0x00, 0x00, 0x00, 0x00]).toString("base64"); + /** @type { { name: string, value: string, domain: string }[] } */ + const [currentCookie] = await t.getCookies(cookieName); + await t.expect(currentCookie).ok(); + await t.setCookies({ ...currentCookie, value: cookieValue }); + + // Reload the page + networkLogger.clearLogs(); + await reloadPage(); + await alloy.configure(config); + + // Request the identity and ensure a network request was made + const { + identity: { ECID: cookieEcid }, + } = await alloy.getIdentity(); + await t.expect(networkLogger.acquireEndpointLogs.requests.length).eql(1); + await t.expect(cookieEcid).notEql(networkEcid); +}); diff --git a/packages/browser/test/functional/specs/Identity/C2581.js b/packages/browser/test/functional/specs/Identity/C2581.js new file mode 100644 index 000000000..5d3433a36 --- /dev/null +++ b/packages/browser/test/functional/specs/Identity/C2581.js @@ -0,0 +1,57 @@ +/* +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 } from "testcafe"; +import createFixture from "../../helpers/createFixture/index.js"; +import cookies from "../../helpers/cookies.js"; +import { + compose, + orgMainConfigMain, + debugEnabled, +} from "../../helpers/constants/configParts/index.js"; +import { MAIN_IDENTITY_COOKIE_NAME } from "../../helpers/constants/cookies.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; +import createNetworkLogger from "../../helpers/networkLogger/index.js"; + +const debugEnabledConfig = compose(orgMainConfigMain, debugEnabled); + +const networkLogger = createNetworkLogger(); + +createFixture({ + title: "C2581: Queue events when no ECID available on client", + requestHooks: [networkLogger.edgeEndpointLogs], +}); + +test.meta({ + ID: "C2581", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +test("Test C2581: Queue requests until we receive an ECID.", async () => { + const alloy = createAlloyProxy(); + await alloy.configure(debugEnabledConfig); + // this should get an ECID + await alloy.sendEventAsync(); + // this should wait until the first event returns + // so it can send the ECID in the request + await alloy.sendEvent(); + await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(2); + + // make sure we have an ecid + const identityCookieValue = await cookies.get(MAIN_IDENTITY_COOKIE_NAME); + await t.expect(identityCookieValue).ok("No identity cookie found."); + + // make sure the ecid was sent as part of the second request + await t + .expect(networkLogger.edgeEndpointLogs.requests[1].request.body) + .contains(identityCookieValue); +}); diff --git a/packages/browser/test/functional/specs/Identity/C25822.js b/packages/browser/test/functional/specs/Identity/C25822.js new file mode 100644 index 000000000..772a27e77 --- /dev/null +++ b/packages/browser/test/functional/specs/Identity/C25822.js @@ -0,0 +1,92 @@ +/* +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 } from "testcafe"; +import createNetworkLogger from "../../helpers/networkLogger/index.js"; +import { responseStatus } from "../../helpers/assertions/index.js"; +import createFixture from "../../helpers/createFixture/index.js"; +import { + compose, + orgMainConfigMain, + debugEnabled, +} from "../../helpers/constants/configParts/index.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; + +const networkLogger = createNetworkLogger(); +const config = compose(orgMainConfigMain, debugEnabled); + +createFixture({ + title: "C25822: Event command sends a request with a validated identityMap", + requestHooks: [networkLogger.edgeEndpointLogs], +}); + +test.meta({ + ID: "C25822", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +const badAlloyEventOptions = { + xdm: { + identityMap: { + HYP: [ + { + id: 123, + }, + ], + }, + }, +}; + +test("C25822: Event command validates the identityMap", async () => { + const alloy = createAlloyProxy(); + await alloy.configure(config); + const errorMessage = await alloy.sendEventErrorMessage(badAlloyEventOptions); + await t + .expect(errorMessage) + .ok("Expected the sendEvent command to be rejected"); + + await t.expect(errorMessage).contains("xdm.identityMap.HYP[0].id"); +}); + +const goodAlloyEventOptions = { + xdm: { + identityMap: { + HYP: [ + { + id: "id123", + }, + ], + }, + }, +}; + +test("C25822: Event command sends the identityMap", async () => { + const alloy = createAlloyProxy(); + await alloy.configure(config); + await alloy.sendEvent(goodAlloyEventOptions); + + await responseStatus(networkLogger.edgeEndpointLogs.requests, [200, 207]); + + await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(1); + + const request = JSON.parse( + networkLogger.edgeEndpointLogs.requests[0].request.body, + ); + + await t.expect(request.events[0].xdm.identityMap).eql({ + HYP: [ + { + id: "id123", + }, + ], + }); +}); diff --git a/packages/browser/test/functional/specs/Identity/C5287654.js b/packages/browser/test/functional/specs/Identity/C5287654.js new file mode 100644 index 000000000..472db7c5b --- /dev/null +++ b/packages/browser/test/functional/specs/Identity/C5287654.js @@ -0,0 +1,81 @@ +/* +Copyright 2022 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 } from "testcafe"; +import createFixture from "../../helpers/createFixture/index.js"; +import cookies from "../../helpers/cookies.js"; +import { + compose, + orgMainConfigMain, + debugEnabled, +} from "../../helpers/constants/configParts/index.js"; +import { MAIN_IDENTITY_COOKIE_NAME } from "../../helpers/constants/cookies.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; +import createNetworkLogger from "../../helpers/networkLogger/index.js"; +import getResponseBody from "../../helpers/networkLogger/getResponseBody.js"; +import createConsoleLogger from "../../helpers/consoleLogger/index.js"; + +const debugEnabledConfig = compose(orgMainConfigMain, debugEnabled); +const networkLogger = createNetworkLogger(); + +createFixture({ + title: "C5287654: Cookies are set with sameSite=none", + requestHooks: [networkLogger.edgeEndpointLogs], +}); + +test.meta({ + ID: "C2581", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +test("Test C5287654: Cookies are set with sameSite=none", async () => { + const logger = await createConsoleLogger(); + const alloy = createAlloyProxy(); + await alloy.configure(debugEnabledConfig); + // this should get cookies + await logger.reset(); + await alloy.sendEvent(); + await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(1); + + // make sure we have an ecid + const identityCookieValue = await cookies.get(MAIN_IDENTITY_COOKIE_NAME); + await t.expect(identityCookieValue).ok("No identity cookie found."); + + // make sure the ecid was sent with sameSite = none + const response = JSON.parse( + getResponseBody(networkLogger.edgeEndpointLogs.requests[0]), + ); + + const stateStoreHandle = response.handle.find( + (handle) => handle.type === "state:store", + ); + const identityCookie = stateStoreHandle.payload.find((cookie) => + cookie.key.endsWith("identity"), + ); + await t.expect(identityCookie.attrs).ok(); + await t.expect(identityCookie.attrs.SameSite).eql("None"); + + const logs = await logger.info.getMessagesSinceReset(); + const setCookieAttributes = logs + .filter( + (message) => message.length === 3 && message[1] === "Setting cookie", + ) + .map((message) => message[2]) + .filter( + (cookieSettings) => cookieSettings.name === MAIN_IDENTITY_COOKIE_NAME, + ); + + await t.expect(setCookieAttributes.length).eql(1); + await t.expect(setCookieAttributes[0].sameSite).eql("none"); + await t.expect(setCookieAttributes[0].secure).eql(true); +}); diff --git a/packages/browser/test/functional/specs/Identity/C5594865.js b/packages/browser/test/functional/specs/Identity/C5594865.js new file mode 100644 index 000000000..29f5d219b --- /dev/null +++ b/packages/browser/test/functional/specs/Identity/C5594865.js @@ -0,0 +1,66 @@ +/* +Copyright 2022 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 } from "testcafe"; +import createFixture from "../../helpers/createFixture/index.js"; +import { SECONDARY_TEST_PAGE } from "../../helpers/constants/url.js"; +import { + compose, + orgMainConfigMain, + debugEnabled, + thirdPartyCookiesDisabled, +} from "../../helpers/constants/configParts/index.js"; +import createNetworkLogger from "../../helpers/networkLogger/index.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; +import getReturnedEcid from "../../helpers/networkLogger/getReturnedEcid.js"; + +// We disable third party cookies so that the domains don't share identities +// through the demdex cookies. +const config = compose( + orgMainConfigMain, + debugEnabled, + thirdPartyCookiesDisabled, +); + +const networkLogger = createNetworkLogger(); + +createFixture({ + title: + "C5594865: Identity can be maintained across domains via the adobe_mc query string parameter", + requestHooks: [networkLogger.edgeEndpointLogs], +}); + +test.meta({ + ID: "C5594865", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +test("C5594865: Identity can be maintained across domains via the adobe_mc query string parameter", async () => { + const alloy = createAlloyProxy(); + await alloy.configure(config); + await alloy.sendEvent({}); + const { url: newUrl } = await alloy.appendIdentityToUrl({ + url: SECONDARY_TEST_PAGE, + }); + + await t.navigateTo(newUrl); + await alloy.configure(config); + await alloy.sendEvent({}); + + const [originalEcid, newEcid] = + networkLogger.edgeEndpointLogs.requests.map(getReturnedEcid); + await t.expect(newEcid).eql(originalEcid); + + const { identity } = await alloy.getIdentity(); + await t.expect(identity.ECID).eql(originalEcid); +}); diff --git a/packages/browser/test/functional/specs/Identity/C5594866.js b/packages/browser/test/functional/specs/Identity/C5594866.js new file mode 100644 index 000000000..6e85318c4 --- /dev/null +++ b/packages/browser/test/functional/specs/Identity/C5594866.js @@ -0,0 +1,79 @@ +/* +Copyright 2022 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 } from "testcafe"; +import createFixture from "../../helpers/createFixture/index.js"; +import { + compose, + orgMainConfigMain, + debugEnabled, + thirdPartyCookiesDisabled, + migrationDisabled, +} from "../../helpers/constants/configParts/index.js"; +import createNetworkLogger from "../../helpers/networkLogger/index.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; +import reloadPage from "../../helpers/reloadPage.js"; +import getReturnedEcid from "../../helpers/networkLogger/getReturnedEcid.js"; +import { TEST_PAGE, SECONDARY_TEST_PAGE } from "../../helpers/constants/url.js"; + +// We disable third party cookies so that the domains don't share identities +// through the demdex cookies. +const config = compose( + orgMainConfigMain, + thirdPartyCookiesDisabled, + debugEnabled, + migrationDisabled, +); + +const networkLogger = createNetworkLogger(); + +createFixture({ + title: + "C5594866: Identity can be changed via the adobe_mc query string parameter", + requestHooks: [networkLogger.edgeEndpointLogs], +}); + +test.meta({ + ID: "C5594866", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +test("C5594866: Identity can be changed via the adobe_mc query string parameter", async () => { + const alloy = createAlloyProxy(); + await alloy.configure(config); + // establish an identity cookie + await alloy.sendEvent({}); + + await t.navigateTo(SECONDARY_TEST_PAGE); + await alloy.configure(config); + await alloy.sendEvent({}); + const { url: newUrl } = await alloy.appendIdentityToUrl({ url: TEST_PAGE }); + + await t.navigateTo(newUrl); + await alloy.configure(config); + await alloy.sendEvent({}); + + await reloadPage(""); + await alloy.configure(config); + await alloy.sendEvent({}); + + const [originalEcid, secondaryPageEcid, newEcid, reloadedEcid] = + networkLogger.edgeEndpointLogs.requests.map(getReturnedEcid); + + await t.expect(originalEcid).notEql(secondaryPageEcid); + await t.expect(newEcid).eql(secondaryPageEcid); + await t.expect(reloadedEcid).eql(secondaryPageEcid); + + const { identity } = await alloy.getIdentity(); + await t.expect(identity.ECID).eql(secondaryPageEcid); +}); diff --git a/packages/browser/test/functional/specs/Identity/C5594871.js b/packages/browser/test/functional/specs/Identity/C5594871.js new file mode 100644 index 000000000..a5e4417da --- /dev/null +++ b/packages/browser/test/functional/specs/Identity/C5594871.js @@ -0,0 +1,47 @@ +/* +Copyright 2022 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 } from "testcafe"; +import createFixture from "../../helpers/createFixture/index.js"; +import { + compose, + orgMainConfigMain, + debugEnabled, +} from "../../helpers/constants/configParts/index.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; +import createRandomEcid from "../../helpers/createRandomEcid.js"; +import { TEST_PAGE as TEST_PAGE_URL } from "../../helpers/constants/url.js"; +import createAdobeMC from "../../helpers/createAdobeMC.js"; + +const config = compose(orgMainConfigMain, debugEnabled); + +const id = createRandomEcid(); +const adobemc = createAdobeMC({ id }); + +createFixture({ + url: `${TEST_PAGE_URL}?adobe_mc=${adobemc}`, + title: "C5594871: getIdentity works with adobe_mc query string parameter", + requestHooks: [], +}); + +test.meta({ + ID: "C5594871", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +test("C5594871: getIdentity works with adobe_mc query string parameter", async () => { + const alloy = createAlloyProxy(); + await alloy.configure(config); + const ecid = await alloy.getIdentity(); + await t.expect(ecid.identity.ECID).eql(id); +}); diff --git a/packages/browser/test/functional/specs/Identity/C5594872.js b/packages/browser/test/functional/specs/Identity/C5594872.js new file mode 100644 index 000000000..80875c2c7 --- /dev/null +++ b/packages/browser/test/functional/specs/Identity/C5594872.js @@ -0,0 +1,54 @@ +/* +Copyright 2022 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 } from "testcafe"; +import createFixture from "../../helpers/createFixture/index.js"; +import { TEST_PAGE as TEST_PAGE_URL } from "../../helpers/constants/url.js"; +import { + compose, + orgMainConfigMain, + debugEnabled, +} from "../../helpers/constants/configParts/index.js"; +import createNetworkLogger from "../../helpers/networkLogger/index.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; +import createRandomEcid from "../../helpers/createRandomEcid.js"; +import getReturnedEcid from "../../helpers/networkLogger/getReturnedEcid.js"; +import createAdobeMC from "../../helpers/createAdobeMC.js"; + +const config = compose(orgMainConfigMain, debugEnabled); + +const networkLogger = createNetworkLogger(); + +const id = createRandomEcid(); +// TTL is 5 minutes (300 seconds), but use 400 to account for differences in server time. +const timestamp = new Date().getTime() / 1000 - 400; +const adobemc = createAdobeMC({ timestamp, id }); + +createFixture({ + url: `${TEST_PAGE_URL}?adobe_mc=${adobemc}`, + title: "C5594872: An expired adobe_mc query string parameter is not used", + requestHooks: [networkLogger.edgeEndpointLogs], +}); + +test.meta({ + ID: "C5594872", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +test("C5594872: An expired adobe_mc query string parameter is not used", async () => { + const alloy = createAlloyProxy(); + await alloy.configure(config); + await alloy.sendEvent({}); + const ecid = getReturnedEcid(networkLogger.edgeEndpointLogs.requests[0]); + await t.expect(ecid).notEql(id); +}); diff --git a/packages/browser/test/functional/specs/Identity/C5598188.js b/packages/browser/test/functional/specs/Identity/C5598188.js new file mode 100644 index 000000000..76ed6a035 --- /dev/null +++ b/packages/browser/test/functional/specs/Identity/C5598188.js @@ -0,0 +1,46 @@ +/* +Copyright 2022 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 { + compose, + orgMainConfigMain, + debugEnabled, +} from "../../helpers/constants/configParts/index.js"; +import { TEST_PAGE } from "../../helpers/constants/url.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; +import createFixture from "../../helpers/createFixture/index.js"; +import createConsoleLogger from "../../helpers/consoleLogger/index.js"; + +const config = compose(orgMainConfigMain, debugEnabled, { + orgId: "invalid-org-id@Adobe", +}); + +createFixture({ + url: TEST_PAGE, + title: + "C5598188: Informative error messages are given when an identity cookie fails to be set", +}); + +test.meta({ + ID: "C5598188", + SEVERTIY: "P0", + TEST_RUN: "Regression", +}); + +test("C5598188: Informative error message given when using an invalid orgID", async () => { + const logger = await createConsoleLogger(); + const validAlloy = createAlloyProxy(); + await validAlloy.configure(config); + await validAlloy.sendEvent({}); + await logger.warn.expectMessageMatching(/Identity cookie not found/); + await logger.warn.expectMessageMatching(/invalid-org-id/); +}); diff --git a/packages/browser/test/functional/specs/Identity/C6842980.js b/packages/browser/test/functional/specs/Identity/C6842980.js new file mode 100644 index 000000000..f8d86e520 --- /dev/null +++ b/packages/browser/test/functional/specs/Identity/C6842980.js @@ -0,0 +1,77 @@ +/* +Copyright 2022 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 } from "testcafe"; +import { + compose, + orgMainConfigMain, + debugEnabled, + thirdPartyCookiesDisabled, + migrationDisabled, +} from "../../helpers/constants/configParts/index.js"; +import { TEST_PAGE } from "../../helpers/constants/url.js"; +import createNetworkLogger from "../../helpers/networkLogger/index.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; +import getReturnedEcid from "../../helpers/networkLogger/getReturnedEcid.js"; +import createFixture from "../../helpers/createFixture/index.js"; +import reloadPage from "../../helpers/reloadPage.js"; +import cookies from "../../helpers/cookies.js"; +import { MAIN_IDENTITY_COOKIE_NAME } from "../../helpers/constants/cookies.js"; + +const networkLogger = createNetworkLogger(); +const config = compose( + orgMainConfigMain, + debugEnabled, + thirdPartyCookiesDisabled, + migrationDisabled, +); + +createFixture({ + url: TEST_PAGE, + title: "C6842980: FPID from the identityMap is used to generate an ECID", + requestHooks: [networkLogger.edgeEndpointLogs], +}); + +test.meta({ + ID: "C6842980", + SEVERTIY: "P0", + TEST_RUN: "Regression", +}); + +const fpid = { + xdm: { + identityMap: { + FPID: [ + { + id: "UUID", + }, + ], + }, + }, +}; + +test("C6842980: FPID from the identityMap generates ECID", async () => { + const alloy = createAlloyProxy(); + + await alloy.configure(config); + await alloy.sendEvent(fpid); + const ecid = getReturnedEcid(networkLogger.edgeEndpointLogs.requests[0]); + + await reloadPage(); + await cookies.remove(MAIN_IDENTITY_COOKIE_NAME); + await alloy.configure(config); + await alloy.sendEvent(fpid); + const ecidCompare = getReturnedEcid( + networkLogger.edgeEndpointLogs.requests[1], + ); + await t.expect(ecid).eql(ecidCompare); +}); diff --git a/packages/browser/test/functional/specs/Identity/C6842981.js b/packages/browser/test/functional/specs/Identity/C6842981.js new file mode 100644 index 000000000..68461f2e2 --- /dev/null +++ b/packages/browser/test/functional/specs/Identity/C6842981.js @@ -0,0 +1,90 @@ +/* +Copyright 2022 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 } from "testcafe"; +import { v4 as uuidv4 } from "uuid"; +import { + compose, + orgMainConfigMain, + debugEnabled, + migrationDisabled, + thirdPartyCookiesDisabled, + edgeDomainFirstParty, +} from "../../helpers/constants/configParts/index.js"; +import { TEST_PAGE } from "../../helpers/constants/url.js"; +import createNetworkLogger from "../../helpers/networkLogger/index.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; +import getReturnedEcid from "../../helpers/networkLogger/getReturnedEcid.js"; +import createFixture from "../../helpers/createFixture/index.js"; +import reloadPage from "../../helpers/reloadPage.js"; +import cookies from "../../helpers/cookies.js"; +import { MAIN_IDENTITY_COOKIE_NAME } from "../../helpers/constants/cookies.js"; + +const networkLogger = createNetworkLogger(); +const config = compose( + orgMainConfigMain, + debugEnabled, + migrationDisabled, + thirdPartyCookiesDisabled, + edgeDomainFirstParty, +); + +createFixture({ + url: TEST_PAGE, + title: "C6842981: FPID from a custom FPID cookie is used to generate an ECID", + requestHooks: [networkLogger.edgeEndpointLogs], +}); + +test.meta({ + ID: "C6842981", + SEVERTIY: "P0", + TEST_RUN: "Regression", +}); + +test("C6842981: FPID from a custom FPID cookie generates an ECID", async () => { + const value = uuidv4(); + + // TestCafe uses Native automation when running tests in Chrome. For this case, the cookie need + // to be set to `.allioyio.com` and not `alloyio.com`. For Firefox, TestCase uses a reverse proxy + // to automate browsers. The emulation is not fully compatible with Native automation. So we need + // to set the cookie also on `alloyio.com` to make the test to pass on other browsers. + await t.setCookies({ + name: "myFPID", + value, + domain: ".alloyio.com", + path: "/", + }); + + await t.setCookies({ + name: "myFPID", + value, + domain: "alloyio.com", + path: "/", + }); + + const alloy = createAlloyProxy(); + await alloy.configure(config); + await alloy.sendEvent(); + + const ecid = getReturnedEcid(networkLogger.edgeEndpointLogs.requests[0]); + await reloadPage(); + + await cookies.remove(MAIN_IDENTITY_COOKIE_NAME); + + await alloy.configure(config); + await alloy.sendEvent(); + + const ecidCompare = getReturnedEcid( + networkLogger.edgeEndpointLogs.requests[1], + ); + await t.expect(ecid).eql(ecidCompare); +}); diff --git a/packages/browser/test/functional/specs/Identity/C6842982.js b/packages/browser/test/functional/specs/Identity/C6842982.js new file mode 100644 index 000000000..aad42e755 --- /dev/null +++ b/packages/browser/test/functional/specs/Identity/C6842982.js @@ -0,0 +1,72 @@ +/* +Copyright 2022 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 } from "testcafe"; +import { + compose, + orgMainConfigMain, + debugEnabled, + thirdPartyCookiesDisabled, + migrationDisabled, +} from "../../helpers/constants/configParts/index.js"; +import { TEST_PAGE } from "../../helpers/constants/url.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; +import createFixture from "../../helpers/createFixture/index.js"; +import createNetworkLogger from "../../helpers/networkLogger/index.js"; +import getReturnedEcid from "../../helpers/networkLogger/getReturnedEcid.js"; + +const networkLogger = createNetworkLogger(); +const config = compose( + orgMainConfigMain, + debugEnabled, + thirdPartyCookiesDisabled, + migrationDisabled, +); + +createFixture({ + url: TEST_PAGE, + title: + "C6842982: existing identity cookie takes precedence over an FPID provided in the identity map.", + requestHooks: [networkLogger.edgeEndpointLogs], +}); + +test.meta({ + ID: "C6842982", + SEVERTIY: "P0", + TEST_RUN: "Regression", +}); + +const fpid = { + xdm: { + identityMap: { + FPID: [ + { + id: "UUID", + }, + ], + }, + }, +}; + +test("C6842982: identity cookie takes precedence over an FPID", async () => { + const alloy = createAlloyProxy(); + await alloy.configure(config); + await alloy.sendEvent(); + const ecid = await getReturnedEcid( + networkLogger.edgeEndpointLogs.requests[0], + ); + await alloy.sendEvent(fpid); + const ecidCompare = getReturnedEcid( + networkLogger.edgeEndpointLogs.requests[1], + ); + await t.expect(ecid).eql(ecidCompare); +}); diff --git a/packages/browser/test/functional/specs/Install SDK/C1338399.js b/packages/browser/test/functional/specs/Install SDK/C1338399.js new file mode 100644 index 000000000..df1e38415 --- /dev/null +++ b/packages/browser/test/functional/specs/Install SDK/C1338399.js @@ -0,0 +1,52 @@ +/* +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 createNetworkLogger from "../../helpers/networkLogger/index.js"; +import { + compose, + orgMainConfigMain, + debugEnabled, + migrationDisabled, +} from "../../helpers/constants/configParts/index.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; + +const mainConfig = compose(orgMainConfigMain, debugEnabled, migrationDisabled); + +const networkLogger = createNetworkLogger(); + +createFixture({ + title: "C1338399: Use SDK from NPM entry point", + includeAlloyLibrary: false, + includeNpmLibrary: true, + requestHooks: [networkLogger.edgeEndpointLogs], +}); + +const createAlloyInstance = ClientFunction(() => { + window.npmLibraryAlloy = window.alloyCreateInstance({ + name: "npmLibraryAlloy", + }); +}); + +test.meta({ + ID: "C1338399: Use SDK from NPM entry point", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +test("C1338399: Use SDK from NPM entry point", async () => { + await createAlloyInstance(); + const alloy = createAlloyProxy("npmLibraryAlloy"); + await alloy.configure(mainConfig); + await alloy.sendEvent(); + await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(1); +}); diff --git a/packages/browser/test/functional/specs/Install SDK/C2560.js b/packages/browser/test/functional/specs/Install SDK/C2560.js new file mode 100644 index 000000000..20f1da8b9 --- /dev/null +++ b/packages/browser/test/functional/specs/Install SDK/C2560.js @@ -0,0 +1,30 @@ +/* +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"; + +const getAlloyFunction = ClientFunction(() => !!window.alloy); + +createFixture({ + title: "C2560: Global function named alloy is accessible.", +}); + +test.meta({ + ID: "C2560", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +test("Test C2560: The global function named alloy is accessible.", async () => { + const alloy = await getAlloyFunction(); + await t.expect(alloy).ok(); +}); diff --git a/packages/browser/test/functional/specs/Install SDK/C2579.js b/packages/browser/test/functional/specs/Install SDK/C2579.js new file mode 100644 index 000000000..c7a72c90e --- /dev/null +++ b/packages/browser/test/functional/specs/Install SDK/C2579.js @@ -0,0 +1,85 @@ +/* +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 { RequestLogger, t } from "testcafe"; +import createFixture from "../../helpers/createFixture/index.js"; +import { + compose, + orgMainConfigMain, + orgAltConfigAlt, + debugEnabled, + migrationDisabled, +} from "../../helpers/constants/configParts/index.js"; +import DATASTREAM_ID from "../../helpers/constants/datastreamId.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; + +const mainConfig = compose(orgMainConfigMain, debugEnabled, migrationDisabled); +const altConfig = compose(orgAltConfigAlt, debugEnabled, migrationDisabled); + +const networkLoggerConfig = { + logRequestBody: true, + stringifyRequestBody: true, +}; +const networkLogger1 = RequestLogger( + /v1\/(interact|collect)\?configId=9999999/, + networkLoggerConfig, +); + +const networkLogger2 = RequestLogger( + new RegExp(`v1\\/(interact|collect)\\?configId=${DATASTREAM_ID}`), + networkLoggerConfig, +); + +createFixture({ + title: "C2579: Isolates multiple SDK instances", + requestHooks: [networkLogger1, networkLogger2], +}); + +test.meta({ + ID: "C2579", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +const getIdentityCookieValue = (request) => { + const payload = JSON.parse(request.request.body); + if (!payload.meta.state.entries) { + return undefined; + } + const identityEntry = payload.meta.state.entries.find((entry) => + entry.key.includes("_identity"), + ); + return identityEntry.value; +}; + +test("Test C2579: Separate ECIDs are used for multiple SDK instances.", async () => { + const instance1 = createAlloyProxy(); + const instance2 = createAlloyProxy("instance2"); + await instance1.configure(altConfig); + await instance2.configure(mainConfig); + await instance1.sendEvent(); + await instance2.sendEvent(); + await instance1.sendEvent(); + await instance2.sendEvent(); + + await t.expect(networkLogger1.requests.length).eql(2); + await t.expect(networkLogger2.requests.length).eql(2); + const id1a = getIdentityCookieValue(networkLogger1.requests[0]); + const id1b = getIdentityCookieValue(networkLogger1.requests[1]); + const id2a = getIdentityCookieValue(networkLogger2.requests[0]); + const id2b = getIdentityCookieValue(networkLogger2.requests[1]); + + await t.expect(id1a).eql(undefined); + await t.expect(id1b).notEql(undefined); + await t.expect(id2a).eql(undefined); + await t.expect(id2b).notEql(undefined); + await t.expect(id1b).notEql(id2b); +}); diff --git a/packages/browser/test/functional/specs/LibraryInfo/C2589.js b/packages/browser/test/functional/specs/LibraryInfo/C2589.js new file mode 100644 index 000000000..25335b0e6 --- /dev/null +++ b/packages/browser/test/functional/specs/LibraryInfo/C2589.js @@ -0,0 +1,125 @@ +/* +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 { ClientFunction, t } from "testcafe"; +import createFixture from "../../helpers/createFixture/index.js"; + +import { + compose, + debugEnabled, + orgMainConfigMain, +} from "../../helpers/constants/configParts/index.js"; + +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; +import { + ADOBE_JOURNEY_OPTIMIZER, + ADOBE_TARGET, +} from "../../../../../core/src/constants/decisionProvider.js"; +import { + ALWAYS, + NEVER, +} from "../../../../../core/src/constants/propositionInteractionType.js"; + +const debugEnabledConfig = compose(orgMainConfigMain, debugEnabled, { + onBeforeEventSend: () => {}, +}); + +createFixture({ + title: "C2589: getLibraryInfo command returns library information", +}); + +test.meta({ + ID: "C2589", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +test("C2589: getLibraryInfo command returns library information.", async () => { + const currentVersion = process.env.npm_package_version; + const currentCommand = [ + "appendIdentityToUrl", + "applyPropositions", + "applyResponse", + "configure", + "createEventMergeId", + "createMediaSession", + "evaluateRulesets", + "getIdentity", + "getLibraryInfo", + "getMediaAnalyticsTracker", + "sendEvent", + "sendMediaEvent", + "sendPushSubscription", + "setConsent", + "setDebug", + "subscribeRulesetItems", + ]; + const currentConfigs = { + clickCollectionEnabled: true, + clickCollection: { + downloadLinkEnabled: true, + eventGroupingEnabled: false, + externalLinkEnabled: true, + internalLinkEnabled: true, + sessionStorageEnabled: false, + }, + context: ["web", "device", "environment", "placeContext"], + debugEnabled: true, + defaultConsent: "in", + downloadLinkQualifier: + "\\.(exe|zip|wav|mp3|mov|mpg|avi|wmv|pdf|doc|docx|xls|xlsx|ppt|pptx)$", + datastreamId: "bc1a10e0-aee4-4e0e-ac5b-cdbb9abbec83", + edgeDomain: "edge.adobedc.net", + idMigrationEnabled: true, + onBeforeEventSend: "() => {}", + orgId: "5BFE274A5F6980A50A495C08@AdobeOrg", + thirdPartyCookiesEnabled: true, + targetMigrationEnabled: false, + personalizationStorageEnabled: false, + autoCollectPropositionInteractions: { + [ADOBE_JOURNEY_OPTIMIZER]: ALWAYS, + [ADOBE_TARGET]: NEVER, + }, + }; + + const alloy = createAlloyProxy(); + await alloy.configure(debugEnabledConfig); + const { libraryInfo } = await alloy.getLibraryInfo(); + delete libraryInfo.configs.edgeBasePath; + await t.expect(libraryInfo.version).eql(currentVersion); + await t.expect(libraryInfo.commands).eql(currentCommand); + await t.expect(libraryInfo.configs).eql(currentConfigs); +}); + +test("C2589: getLibraryInfo correctly serializes functions in the config", async () => { + const alloy = createAlloyProxy(); + await alloy.configure(debugEnabledConfig); + const { libraryInfo } = await alloy.getLibraryInfo(); + await t.expect(typeof libraryInfo.configs.onBeforeEventSend).eql("string"); +}); + +test("C2589: libraryInfo can be marshaled to postMessage", async () => { + const instanceName = "alloy"; + const alloy = createAlloyProxy(instanceName); + await alloy.configure(debugEnabledConfig); + const postLibraryInfo = ClientFunction( + () => { + return window[instanceName]("getLibraryInfo").then(({ libraryInfo }) => { + window.postMessage(libraryInfo, "*"); + }); + }, + { dependencies: { instanceName } }, + ); + const result = await postLibraryInfo(); + // This is really just asserting that we got this far. If libraryInfo cannot be + // marshaled, postLibraryInfo() will throw an exception about cloning functions. + await t.expect(result).notOk("getLibraryInfo can be marshaled successfully"); +}); diff --git a/packages/browser/test/functional/specs/Location Hints/C6589015.js b/packages/browser/test/functional/specs/Location Hints/C6589015.js new file mode 100644 index 000000000..bc5413262 --- /dev/null +++ b/packages/browser/test/functional/specs/Location Hints/C6589015.js @@ -0,0 +1,61 @@ +/* +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 } from "testcafe"; +import createNetworkLogger from "../../helpers/networkLogger/index.js"; +import cookies from "../../helpers/cookies.js"; +import createFixture from "../../helpers/createFixture/index.js"; +import { + compose, + orgMainConfigMain, + thirdPartyCookiesDisabled, + debugEnabled, +} from "../../helpers/constants/configParts/index.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; +import { MAIN_CLUSTER_COOKIE_NAME } from "../../helpers/constants/cookies.js"; + +const networkLogger = createNetworkLogger(); +const config = compose( + orgMainConfigMain, + debugEnabled, + thirdPartyCookiesDisabled, +); + +createFixture({ + title: + "C6589015: The Experience Edge location hint is used on the second request.", + requestHooks: [networkLogger.edgeEndpointLogs], +}); + +test.meta({ + ID: "C6589015", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +test("Test C6589015: The Experience Edge location hint is used on the second request.", async () => { + const alloy = createAlloyProxy(); + await alloy.configure(config); + await alloy.sendEvent({}); + + const locationHint = await cookies.get(MAIN_CLUSTER_COOKIE_NAME); + await t.expect(locationHint).ok(); + + await alloy.sendEvent({}); + + const urls = networkLogger.edgeEndpointLogs.requests.map( + (r) => r.request.url, + ); + await t.expect(urls[0]).match(/^https:\/\/[^/]+\/[^/]+\/v1\/interact/); + await t + .expect(urls[1]) + .match(new RegExp(`^https://[^/]+/[^/]+/${locationHint}/v1/interact`)); +}); diff --git a/packages/browser/test/functional/specs/Location Hints/C6944931.js b/packages/browser/test/functional/specs/Location Hints/C6944931.js new file mode 100644 index 000000000..5b2f1473a --- /dev/null +++ b/packages/browser/test/functional/specs/Location Hints/C6944931.js @@ -0,0 +1,65 @@ +/* +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 } from "testcafe"; +import createNetworkLogger from "../../helpers/networkLogger/index.js"; +import cookies from "../../helpers/cookies.js"; +import createFixture from "../../helpers/createFixture/index.js"; +import { + compose, + orgMainConfigMain, + thirdPartyCookiesDisabled, + debugEnabled, +} from "../../helpers/constants/configParts/index.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; +import { MAIN_CLUSTER_COOKIE_NAME } from "../../helpers/constants/cookies.js"; + +const networkLogger = createNetworkLogger(); +const config = compose( + orgMainConfigMain, + debugEnabled, + thirdPartyCookiesDisabled, +); + +createFixture({ + title: "C6944931: The legacy Adobe Target location hint is used.", + requestHooks: [networkLogger.edgeEndpointLogs], +}); + +test.meta({ + ID: "C6944931", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +test("Test C6944931: The legacy Adobe Target location hint is used.", async () => { + // 38 = singapore, Konductor region ID 3 + await t.setCookies({ + name: "mboxEdgeCluster", + value: "38", + domain: "alloyio.com", + path: "/", + }); + const alloy = createAlloyProxy(); + await alloy.configure(config); + await alloy.sendEvent({}); + + const locationHint = await cookies.get(MAIN_CLUSTER_COOKIE_NAME); + await t.expect(locationHint).eql("sgp3"); + + await alloy.sendEvent({}); + + const urls = networkLogger.edgeEndpointLogs.requests.map( + (r) => r.request.url, + ); + await t.expect(urls[0]).match(/^https:\/\/[^/]+\/[^/]+\/t38\/v1\/interact/); + await t.expect(urls[1]).match(/^https:\/\/[^/]+\/[^/]+\/sgp3\/v1\/interact/); +}); diff --git a/packages/browser/test/functional/specs/Logging/C2583.js b/packages/browser/test/functional/specs/Logging/C2583.js new file mode 100644 index 000000000..e9dbd6b86 --- /dev/null +++ b/packages/browser/test/functional/specs/Logging/C2583.js @@ -0,0 +1,57 @@ +/* +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 createFixture from "../../helpers/createFixture/index.js"; +import { + compose, + orgMainConfigMain, + debugEnabled, + debugDisabled, +} from "../../helpers/constants/configParts/index.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; + +const debugEnabledConfig = compose(orgMainConfigMain, debugEnabled); + +const debugDisabledConfig = compose(orgMainConfigMain, debugDisabled); + +createFixture({ + title: "C2583: Toggle logging through configuration", +}); + +test.meta({ + ID: "C2583", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +test("Test C2583: Set the log option to true. Load the page. Execute a sendEvent command.", async (t) => { + const alloy = createAlloyProxy(); + await alloy.configure(debugEnabledConfig); + await alloy.sendEvent(); + + const { info } = await t.getBrowserConsoleMessages(); + + await t.expect(info).match(/\[alloy] Executing sendEvent command./); +}); + +test("Test C2583: Set the log option in the configuration to false. Refresh the browser. Execute a sendEvent command.", async (t) => { + const alloy = createAlloyProxy(); + await alloy.configure(debugDisabledConfig); + await alloy.sendEvent(); + + const { info } = await t.getBrowserConsoleMessages(); + + await t.expect(info).notContains("Executing sendEvent command."); + + await alloy.sendEvent(); + + await t.expect(info).notContains("Executing sendEvent command."); +}); diff --git a/packages/browser/test/functional/specs/Logging/C2584.js b/packages/browser/test/functional/specs/Logging/C2584.js new file mode 100644 index 000000000..3d49d7438 --- /dev/null +++ b/packages/browser/test/functional/specs/Logging/C2584.js @@ -0,0 +1,42 @@ +/* +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 createConsoleLogger from "../../helpers/consoleLogger/index.js"; +import createFixture from "../../helpers/createFixture/index.js"; +import { orgMainConfigMain } from "../../helpers/constants/configParts/index.js"; +import reloadPage from "../../helpers/reloadPage.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; + +createFixture({ + title: "C2584: Toggle logging through setDebug command", +}); + +test.meta({ + ID: "C2584", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +test("Test C2584: setDebug command with enable: true. getLibraryInfo. refresh. toggle and repeat.", async () => { + const logger = await createConsoleLogger(); + const alloy = createAlloyProxy(); + await alloy.configure(orgMainConfigMain); + await alloy.setDebug({ enabled: true }); + await alloy.getLibraryInfo(); + await logger.info.expectMessageMatching(/Executing getLibraryInfo command/); + + await reloadPage(); + await alloy.configure(orgMainConfigMain); + await alloy.setDebug({ enabled: false }); + await logger.reset(); + await alloy.getLibraryInfo(); + await logger.info.expectNoMessages(); +}); diff --git a/packages/browser/test/functional/specs/Logging/C2586.js b/packages/browser/test/functional/specs/Logging/C2586.js new file mode 100644 index 000000000..1187f04b9 --- /dev/null +++ b/packages/browser/test/functional/specs/Logging/C2586.js @@ -0,0 +1,35 @@ +/* +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 createFixture from "../../helpers/createFixture/index.js"; +import { TEST_PAGE as TEST_PAGE_URL } from "../../helpers/constants/url.js"; +import { orgMainConfigMain } from "../../helpers/constants/configParts/index.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; + +createFixture({ + title: "C2586: Toggle logging through the querystring parameter.", + url: `${TEST_PAGE_URL}?alloy_debug=true`, +}); + +test.meta({ + ID: "C2586", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +test("Test C2586: Toggle logging through the querystring parameter.", async (t) => { + const alloy = createAlloyProxy(); + await alloy.configure(orgMainConfigMain); + await alloy.getLibraryInfo(); + + const { info } = await t.getBrowserConsoleMessages(); + await t.expect(info).match(/Executing getLibraryInfo command/); +}); diff --git a/packages/browser/test/functional/specs/Logging/C532204.js b/packages/browser/test/functional/specs/Logging/C532204.js new file mode 100644 index 000000000..ac7cea20d --- /dev/null +++ b/packages/browser/test/functional/specs/Logging/C532204.js @@ -0,0 +1,58 @@ +/* +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 { ClientFunction } from "testcafe"; +import createFixture from "../../helpers/createFixture/index.js"; +import { + compose, + orgMainConfigMain, + debugEnabled, +} from "../../helpers/constants/configParts/index.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; + +const debugEnabledConfig = compose(orgMainConfigMain, debugEnabled); + +/* + * Some pages will redefine the console logging methods with implementations + * that aren't as forgiving as the built in logger. We ran into this issue + * on a Shopify site with a redefined logger. This test runs through some basic + * scenarios and makes sure the logged objects can be stringified + */ +createFixture({ + title: "C532204: Logged objects can be stringified", +}); + +test.meta({ + ID: "C532204", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +const setupLogger = ClientFunction(() => { + ["log", "info", "warn", "error"].forEach((methodName) => { + // eslint-disable-next-line no-console + const origConsoleMethod = console[methodName]; + // eslint-disable-next-line no-console + console[methodName] = (...args) => { + args.forEach((arg) => { + String(arg); + }); + origConsoleMethod.apply(console, args); + }; + }); +}); + +test("Test C532204: Logged objects can be stringified", async () => { + await setupLogger(); + const alloy = createAlloyProxy(); + await alloy.configure(debugEnabledConfig); + await alloy.sendEvent(); +}); diff --git a/packages/browser/test/functional/specs/MediaCollection/MA1.js b/packages/browser/test/functional/specs/MediaCollection/MA1.js new file mode 100644 index 000000000..ddd3636ea --- /dev/null +++ b/packages/browser/test/functional/specs/MediaCollection/MA1.js @@ -0,0 +1,302 @@ +/* +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 { t } from "testcafe"; +import createNetworkLogger from "../../helpers/networkLogger/index.js"; +import { responseStatus } from "../../helpers/assertions/index.js"; +import createFixture from "../../helpers/createFixture/index.js"; +import { compose } from "../../helpers/constants/configParts/index.js"; +import getResponseBody from "../../helpers/networkLogger/getResponseBody.js"; +import createResponse from "../../helpers/createResponse.js"; +import { TEST_PAGE as TEST_PAGE_URL } from "../../helpers/constants/url.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; +import orgMediaConfig from "../../helpers/constants/configParts/orgMediaConfig.js"; +import streamingMedia from "../../helpers/constants/configParts/streamingMedia.js"; +import { sleep } from "../Migration/helper.js"; + +const networkLogger = createNetworkLogger(); +const config = compose(orgMediaConfig, streamingMedia); +createFixture({ + title: "Streaming media in automatic mode.", + url: TEST_PAGE_URL, + requestHooks: [ + networkLogger.edgeEndpointLogs, + networkLogger.mediaPauseEndpointLogs, + networkLogger.mediaPlayEndpointLogs, + networkLogger.chapterStartEndpointLogs, + networkLogger.pingEndpointLogs, + networkLogger.chapterCompleteEndpointLogs, + networkLogger.chapterSkipEndpointLogs, + networkLogger.adStartEndpointLogs, + networkLogger.adBreakStartEndpointLogs, + networkLogger.adBreakCompleteEndpointLogs, + networkLogger.adSkipEndpointLogs, + networkLogger.adCompleteEndpointLogs, + networkLogger.errorEndpointLogs, + networkLogger.sessionCompleteEndpointLogs, + networkLogger.sessionEndEndpointLogs, + networkLogger.statesUpdateEndpointLogs, + networkLogger.bitrateChangeEndpointLogs, + ], +}); + +test.meta({ + ID: "MA1", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); +const assertSessionStartedInAutoPingMode = async (alloy) => { + const sessionPromise = await alloy.createMediaSession({ + playerId: "player1", + xdm: { + mediaCollection: { + sessionDetails: { + length: 60, + contentType: "VOD", + name: "test name of the video", + }, + }, + }, + getPlayerDetails: () => { + return { + playhead: 3, + qoeDataDetails: { + bitrate: 1, + droppedFrames: 2, + framesPerSecond: 3, + timeToStart: 4, + }, + }; + }, + }); + await responseStatus(networkLogger.edgeEndpointLogs.requests, [200, 207]); + await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(1); + + const createSession = networkLogger.edgeEndpointLogs.requests[0]; + const requestBody = JSON.parse(createSession.request.body); + await t.expect(requestBody.events[0].xdm.eventType).eql("media.sessionStart"); + await t.expect(requestBody.events[0].xdm.mediaCollection.playhead).eql(3); + const response = JSON.parse( + getResponseBody(networkLogger.edgeEndpointLogs.requests[0]), + ); + const mediaCollectionPayload = createResponse({ + content: response, + }).getPayloadsByType("media-analytics:new-session"); + + await t + .expect(mediaCollectionPayload[0].sessionId) + .eql(sessionPromise.sessionId); + + return sessionPromise; +}; +const assertPingsSent = async (sessionId) => { + const pingEventRequest = networkLogger.pingEndpointLogs.requests[0]; + const pingEvent = JSON.parse(pingEventRequest.request.body).events[0]; + await t.expect(pingEvent.xdm.mediaCollection.sessionID).eql(sessionId); + await t.expect(pingEvent.xdm.eventType).eql("media.ping"); +}; +const assertPingsNotSentWhenSessionClosed = async (alloy) => { + await alloy.sendMediaEvent({ + playerId: "player1", + xdm: { + eventType: "media.sessionComplete", + }, + }); + await sleep(10000); + + const secondPingEventRequest = networkLogger.pingEndpointLogs.requests[2]; + await t.expect(secondPingEventRequest).eql(undefined); +}; +const sendMediaEvent = async ( + alloy, + eventType, + sessionId, + additionalData = {}, +) => { + await alloy.sendMediaEvent({ + playerId: "player1", + xdm: { + eventType, + mediaCollection: { + ...additionalData, + }, + }, + }); +}; + +const assertEventIsSent = async (endpointLogs, eventType, sessionId) => { + const eventRequest = endpointLogs.requests[0]; + await responseStatus(endpointLogs.requests, 204); + + const event = JSON.parse(eventRequest.request.body).events[0]; + await t.expect(event.xdm.mediaCollection.playhead).eql(3); + await t.expect(event.xdm.mediaCollection.sessionID).eql(sessionId); + await t.expect(event.xdm.eventType).eql(eventType); +}; + +test("Test that MC component sends pings, augment the events with playhead and session", async () => { + const alloy = createAlloyProxy(); + await alloy.configure(config); + const { sessionId } = await assertSessionStartedInAutoPingMode(alloy); + await sleep(11000); + await assertPingsSent(sessionId); + + // play event + await sendMediaEvent(alloy, "media.play", sessionId); + await assertEventIsSent( + networkLogger.mediaPlayEndpointLogs, + "media.play", + sessionId, + ); + + // pause event + await sendMediaEvent(alloy, "media.pauseStart", sessionId); + await assertEventIsSent( + networkLogger.mediaPauseEndpointLogs, + "media.pauseStart", + sessionId, + ); + + // chapter start event + await sendMediaEvent(alloy, "media.chapterStart", sessionId, { + chapterDetails: { + friendlyName: "Chapter 1", + length: 10, + index: 1, + offset: 0, + }, + }); + await assertEventIsSent( + networkLogger.chapterStartEndpointLogs, + "media.chapterStart", + sessionId, + ); + + await sendMediaEvent(alloy, "media.chapterComplete", sessionId); + await assertEventIsSent( + networkLogger.chapterCompleteEndpointLogs, + "media.chapterComplete", + sessionId, + ); + + await sendMediaEvent(alloy, "media.chapterSkip", sessionId); + await assertEventIsSent( + networkLogger.chapterSkipEndpointLogs, + "media.chapterSkip", + sessionId, + ); + + await sendMediaEvent(alloy, "media.adBreakStart", sessionId, { + advertisingPodDetails: { + friendlyName: "Mid-roll", + offset: 0, + index: 1, + }, + }); + await assertEventIsSent( + networkLogger.adBreakStartEndpointLogs, + "media.adBreakStart", + sessionId, + ); + + await sendMediaEvent(alloy, "media.adStart", sessionId, { + advertisingDetails: { + friendlyName: "Ad 1", + name: "/uri-reference/001", + length: 10, + advertiser: "Adobe Marketing", + campaignID: "Adobe Analytics", + creativeID: "creativeID", + creativeURL: "https://creativeurl.com", + placementID: "placementID", + siteID: "siteID", + podPosition: 11, + playerName: "HTML5 player", + }, + }); + await assertEventIsSent( + networkLogger.adStartEndpointLogs, + "media.adStart", + sessionId, + ); + + await sendMediaEvent(alloy, "media.adComplete", sessionId); + await assertEventIsSent( + networkLogger.adCompleteEndpointLogs, + "media.adComplete", + sessionId, + ); + + await sendMediaEvent(alloy, "media.adBreakComplete", sessionId); + await assertEventIsSent( + networkLogger.adBreakCompleteEndpointLogs, + "media.adBreakComplete", + sessionId, + ); + + await sendMediaEvent(alloy, "media.adSkip", sessionId); + await assertEventIsSent( + networkLogger.adSkipEndpointLogs, + "media.adSkip", + sessionId, + ); + + await sendMediaEvent(alloy, "media.error", sessionId, { + errorDetails: { + name: "test-buffer-start", + source: "player", + }, + }); + await assertEventIsSent( + networkLogger.errorEndpointLogs, + "media.error", + sessionId, + ); + + await sendMediaEvent(alloy, "media.bitrateChange", sessionId, { + qoeDataDetails: { + framesPerSecond: 1, + bitrate: 35000, + droppedFrames: 30, + timeToStart: 1364, + }, + }); + await assertEventIsSent( + networkLogger.bitrateChangeEndpointLogs, + "media.bitrateChange", + sessionId, + ); + + await sendMediaEvent(alloy, "media.statesUpdate", sessionId, { + statesStart: [ + { + name: "mute", + }, + { + name: "pictureInPicture", + }, + ], + statesEnd: [ + { + name: "fullScreen", + }, + ], + }); + await assertEventIsSent( + networkLogger.statesUpdateEndpointLogs, + "media.statesUpdate", + sessionId, + ); + + await sleep(11000); + await assertPingsSent(sessionId); + await assertPingsNotSentWhenSessionClosed(alloy); +}); diff --git a/packages/browser/test/functional/specs/MediaCollection/MA2.js b/packages/browser/test/functional/specs/MediaCollection/MA2.js new file mode 100644 index 000000000..8f10fb3e1 --- /dev/null +++ b/packages/browser/test/functional/specs/MediaCollection/MA2.js @@ -0,0 +1,384 @@ +/* +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 { ClientFunction, t } from "testcafe"; +import createNetworkLogger from "../../helpers/networkLogger/index.js"; +import { responseStatus } from "../../helpers/assertions/index.js"; +import createFixture from "../../helpers/createFixture/index.js"; +import { compose } from "../../helpers/constants/configParts/index.js"; +import getResponseBody from "../../helpers/networkLogger/getResponseBody.js"; +import createResponse from "../../helpers/createResponse.js"; +import { TEST_PAGE as TEST_PAGE_URL } from "../../helpers/constants/url.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; +import orgMediaConfig from "../../helpers/constants/configParts/orgMediaConfig.js"; +import streamingMedia from "../../helpers/constants/configParts/streamingMedia.js"; +import { sleep } from "../Migration/helper.js"; + +const networkLogger = createNetworkLogger(); +const config = compose(orgMediaConfig, streamingMedia); +createFixture({ + title: "Streaming media for legacy migration use cases.", + url: TEST_PAGE_URL, + requestHooks: [ + networkLogger.edgeEndpointLogs, + networkLogger.mediaPauseEndpointLogs, + networkLogger.mediaPlayEndpointLogs, + networkLogger.chapterStartEndpointLogs, + networkLogger.pingEndpointLogs, + networkLogger.chapterCompleteEndpointLogs, + networkLogger.chapterSkipEndpointLogs, + networkLogger.adStartEndpointLogs, + networkLogger.adBreakStartEndpointLogs, + networkLogger.adBreakCompleteEndpointLogs, + networkLogger.adSkipEndpointLogs, + networkLogger.adCompleteEndpointLogs, + networkLogger.errorEndpointLogs, + networkLogger.sessionCompleteEndpointLogs, + networkLogger.sessionEndEndpointLogs, + networkLogger.statesUpdateEndpointLogs, + networkLogger.bitrateChangeEndpointLogs, + networkLogger.bufferStartEndpointLogs, + ], +}); + +test.meta({ + ID: "MA3", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +const assertSessionStarted = async () => { + await t.expect(networkLogger.edgeEndpointLogs.count(() => true)).gte(1); + await responseStatus(networkLogger.edgeEndpointLogs.requests, [200, 207]); + await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(1); + + const createSession = networkLogger.edgeEndpointLogs.requests[0]; + const requestBody = JSON.parse(createSession.request.body); + await t.expect(requestBody.events[0].xdm.eventType).eql("media.sessionStart"); + await t.expect(requestBody.events[0].xdm.mediaCollection.playhead).eql(0); + const response = JSON.parse( + getResponseBody(networkLogger.edgeEndpointLogs.requests[0]), + ); + const mediaCollectionPayload = createResponse({ + content: response, + }).getPayloadsByType("media-analytics:new-session"); + + return mediaCollectionPayload[0].sessionId; +}; + +const assertPingsNotSent = async () => { + await sleep(10000); + const secondPingEventRequest = networkLogger.pingEndpointLogs.requests[2]; + await t.expect(secondPingEventRequest).eql(undefined); +}; +const assertPingsSent = async (sessionId) => { + await t.expect(networkLogger.pingEndpointLogs.count(() => true)).gte(1); + const pingEventRequest = networkLogger.pingEndpointLogs.requests[0]; + const pingEvent = JSON.parse(pingEventRequest.request.body).events[0]; + await t.expect(pingEvent.xdm.mediaCollection.sessionID).eql(sessionId); + await t.expect(pingEvent.xdm.eventType).eql("media.ping"); +}; +const assertEventIsSent = async ( + endpointLogs, + eventType, + sessionId, + playhead, + order = 0, +) => { + await t.expect(endpointLogs.count(() => true)).gte(order + 1); + const eventRequest = endpointLogs.requests[order]; + await responseStatus(endpointLogs.requests, 204); + + const event = JSON.parse(eventRequest.request.body).events[0]; + await t.expect(event.xdm.mediaCollection.sessionID).eql(sessionId); + await t.expect(event.xdm.mediaCollection.playhead).eql(playhead); + await t.expect(event.xdm.eventType).eql(eventType); +}; + +const initializeTracker = ClientFunction(() => { + return window.alloy("getMediaAnalyticsTracker").then((Media) => { + window.Media = Media; + window.mediaTrackerInstance = Media.getInstance(); + return Media; + }); +}); + +const trackEvent = ClientFunction((eventType) => { + const event = window.Media.Event[eventType]; + window.mediaTrackerInstance.trackEvent(event); +}); +const trackPlay = ClientFunction(() => { + window.mediaTrackerInstance.trackPlay(); +}); +const trackPause = ClientFunction(() => { + window.mediaTrackerInstance.trackPause(); +}); +const updatePlayhead = ClientFunction((playhead) => { + window.mediaTrackerInstance.updatePlayhead(playhead); +}); + +const startChapter = ClientFunction(() => { + const chapterContextData = { + segmentType: "Sample segment type", + }; + const chapterInfo = window.Media.createChapterObject( + "chapterNumber1", + 2, + 18, + 1, + ); + window.mediaTrackerInstance.trackEvent( + window.Media.Event.ChapterStart, + chapterInfo, + chapterContextData, + ); +}); + +const trackSessionStart = ClientFunction(() => { + const Media = window.Media; + const tracker = window.mediaTrackerInstance; + const mediaInfo = Media.createMediaObject( + "NinasVideoName", + "Ninas player video", + 60, + Media.StreamType.VOD, + Media.MediaType.Video, + ); + const contextData = { + isUserLoggedIn: "false", + tvStation: "Sample TV station", + programmer: "Sample programmer", + assetID: "/uri-reference", + }; + + contextData[Media.VideoMetadataKeys.Episode] = "Sample Episode"; + contextData[Media.VideoMetadataKeys.Show] = "Sample Show"; + + tracker.trackSessionStart(mediaInfo, contextData); +}); + +const trackAds = ClientFunction(() => { + const tracker = window.mediaTrackerInstance; + + const adObject = window.Media.createAdObject("ad-name", "ad-id", 1, 15.0); + + const adMetadata = {}; + // Standard metadata keys provided by adobe. + adMetadata[window.Media.AdMetadataKeys.Advertiser] = "Sample Advertiser"; + adMetadata[window.Media.AdMetadataKeys.CampaignId] = "Sample Campaign"; + // Custom metadata keys + adMetadata.affiliate = "Sample affiliate"; + + tracker.trackEvent(window.Media.Event.AdStart, adObject, adMetadata); + + // AdComplete + tracker.trackEvent(window.Media.Event.AdComplete); + + // AdSkip + tracker.trackEvent(window.Media.Event.AdSkip); + + // AdBreakStart + const adBreakObject = window.Media.createAdBreakObject("preroll", 1, 0); + tracker.trackEvent(window.Media.Event.AdBreakStart, adBreakObject); + + // AdBreakComplete + tracker.trackEvent(window.Media.Event.AdBreakComplete); +}); + +const trackError = ClientFunction((errorId) => { + window.mediaTrackerInstance.trackError(errorId); +}); + +const trackPlaybackEvents = ClientFunction(() => { + // BufferStart + window.mediaTrackerInstance.trackEvent(window.Media.Event.BufferStart); + + // BufferComplete + window.mediaTrackerInstance.trackEvent(window.Media.Event.BufferComplete); + + // SeekStart + window.mediaTrackerInstance.trackEvent(window.Media.Event.SeekStart); + + // SeekComplete + window.mediaTrackerInstance.trackEvent(window.Media.Event.SeekComplete); +}); + +const bitrateChange = ClientFunction(() => { + const qoeObject = window.Media.createQoEObject(1000000, 24, 25, 10); + window.mediaTrackerInstance.updateQoEObject(qoeObject); + + // Bitrate change + window.mediaTrackerInstance.trackEvent(window.Media.Event.BitrateChange); +}); + +const stateChanges = ClientFunction(() => { + // StateStart (ex: Mute is switched on) + const stateObject = window.Media.createStateObject( + window.Media.PlayerState.Mute, + ); + window.mediaTrackerInstance.trackEvent( + window.Media.Event.StateStart, + stateObject, + ); + + // StateEnd + window.mediaTrackerInstance.trackEvent( + window.Media.Event.StateEnd, + stateObject, + ); +}); + +const sessionComplete = ClientFunction(() => { + window.mediaTrackerInstance.trackComplete(); +}); + +test("Test that legacy component send pings automatically and events are transformed correctly into XDM objects.", async () => { + const alloy = createAlloyProxy(); + await alloy.configure(config); + await initializeTracker(); + await trackSessionStart(); + const sessionId = await assertSessionStarted(); + + // play event + await trackPlay(); + await assertEventIsSent( + networkLogger.mediaPlayEndpointLogs, + "media.play", + sessionId, + 0, + ); + + // pause event + await trackPause(); + await assertEventIsSent( + networkLogger.mediaPauseEndpointLogs, + "media.pauseStart", + sessionId, + 0, + ); + + // chapter start event + await startChapter(); + await assertEventIsSent( + networkLogger.chapterStartEndpointLogs, + "media.chapterStart", + sessionId, + 0, + ); + + await updatePlayhead(10); + + await trackEvent("ChapterComplete"); + + // chapter skip event + await trackEvent("ChapterSkip"); + + await trackPlaybackEvents(); + // bitrate change event + await bitrateChange(); + await stateChanges(); + // error event + await trackError("test-buffer-start"); + // ad break start event + + await trackAds(); + await assertEventIsSent( + networkLogger.chapterCompleteEndpointLogs, + "media.chapterComplete", + sessionId, + 10, + ); + + await assertEventIsSent( + networkLogger.chapterSkipEndpointLogs, + "media.chapterSkip", + sessionId, + 10, + ); + + await assertEventIsSent( + networkLogger.adBreakStartEndpointLogs, + "media.adBreakStart", + sessionId, + 10, + ); + await assertEventIsSent( + networkLogger.adStartEndpointLogs, + "media.adStart", + sessionId, + 10, + ); + await assertEventIsSent( + networkLogger.adCompleteEndpointLogs, + "media.adComplete", + sessionId, + 10, + ); + await assertEventIsSent( + networkLogger.adBreakCompleteEndpointLogs, + "media.adBreakComplete", + sessionId, + 10, + ); + await assertEventIsSent( + networkLogger.adSkipEndpointLogs, + "media.adSkip", + sessionId, + 10, + ); + + await assertEventIsSent( + networkLogger.errorEndpointLogs, + "media.error", + sessionId, + 10, + ); + + await assertEventIsSent( + networkLogger.bufferStartEndpointLogs, + "media.bufferStart", + sessionId, + 10, + ); + await assertEventIsSent( + networkLogger.mediaPlayEndpointLogs, + "media.play", + sessionId, + 10, + 1, + ); + + await assertEventIsSent( + networkLogger.bitrateChangeEndpointLogs, + "media.bitrateChange", + sessionId, + 10, + ); + await assertEventIsSent( + networkLogger.statesUpdateEndpointLogs, + "media.statesUpdate", + sessionId, + 10, + 0, + ); + await assertEventIsSent( + networkLogger.statesUpdateEndpointLogs, + "media.statesUpdate", + sessionId, + 10, + 1, + ); + await sleep(10000); + await assertPingsSent(sessionId); + await sessionComplete(); + await sleep(10000); + await assertPingsNotSent(); +}); diff --git a/packages/browser/test/functional/specs/MediaCollection/MA3.js b/packages/browser/test/functional/specs/MediaCollection/MA3.js new file mode 100644 index 000000000..429a81b0e --- /dev/null +++ b/packages/browser/test/functional/specs/MediaCollection/MA3.js @@ -0,0 +1,286 @@ +/* +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 { t } from "testcafe"; +import createNetworkLogger from "../../helpers/networkLogger/index.js"; +import { responseStatus } from "../../helpers/assertions/index.js"; +import createFixture from "../../helpers/createFixture/index.js"; +import { compose } from "../../helpers/constants/configParts/index.js"; +import getResponseBody from "../../helpers/networkLogger/getResponseBody.js"; +import createResponse from "../../helpers/createResponse.js"; +import { TEST_PAGE as TEST_PAGE_URL } from "../../helpers/constants/url.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; +import orgMediaConfig from "../../helpers/constants/configParts/orgMediaConfig.js"; +import streamingMedia from "../../helpers/constants/configParts/streamingMedia.js"; +import { sleep } from "../Migration/helper.js"; + +const networkLogger = createNetworkLogger(); +const config = compose(orgMediaConfig, streamingMedia); +createFixture({ + title: "Streaming media in non-automatic mode", + url: TEST_PAGE_URL, + requestHooks: [ + networkLogger.edgeEndpointLogs, + networkLogger.mediaPauseEndpointLogs, + networkLogger.mediaPlayEndpointLogs, + networkLogger.chapterStartEndpointLogs, + networkLogger.pingEndpointLogs, + networkLogger.chapterCompleteEndpointLogs, + networkLogger.chapterSkipEndpointLogs, + networkLogger.adStartEndpointLogs, + networkLogger.adBreakStartEndpointLogs, + networkLogger.adBreakCompleteEndpointLogs, + networkLogger.adSkipEndpointLogs, + networkLogger.adCompleteEndpointLogs, + networkLogger.errorEndpointLogs, + networkLogger.sessionCompleteEndpointLogs, + networkLogger.sessionEndEndpointLogs, + networkLogger.statesUpdateEndpointLogs, + networkLogger.bitrateChangeEndpointLogs, + networkLogger.bufferStartEndpointLogs, + ], +}); + +test.meta({ + ID: "MA3", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); +const assertSessionStarted = async (alloy) => { + const sessionPromise = await alloy.createMediaSession({ + xdm: { + mediaCollection: { + playhead: 0, + sessionDetails: { + length: 60, + contentType: "VOD", + name: "test name of the video", + }, + }, + }, + }); + await responseStatus(networkLogger.edgeEndpointLogs.requests, [200, 207]); + await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(1); + + const createSession = networkLogger.edgeEndpointLogs.requests[0]; + const requestBody = JSON.parse(createSession.request.body); + await t.expect(requestBody.events[0].xdm.eventType).eql("media.sessionStart"); + await t.expect(requestBody.events[0].xdm.mediaCollection.playhead).eql(0); + const response = JSON.parse( + getResponseBody(networkLogger.edgeEndpointLogs.requests[0]), + ); + const mediaCollectionPayload = createResponse({ + content: response, + }).getPayloadsByType("media-analytics:new-session"); + await t + .expect(mediaCollectionPayload[0].sessionId) + .eql(sessionPromise.sessionId); + + return sessionPromise; +}; + +const assertPingsNotSent = async () => { + await sleep(10000); + + const secondPingEventRequest = networkLogger.pingEndpointLogs.requests[0]; + await t.expect(secondPingEventRequest).eql(undefined); +}; +const sendMediaEvent = async ( + alloy, + eventType, + sessionId, + additionalData = {}, +) => { + await alloy.sendMediaEvent({ + xdm: { + eventType, + mediaCollection: { + playhead: 1, + sessionID: sessionId, + ...additionalData, + }, + }, + }); +}; + +const assertEventIsSent = async (endpointLogs, eventType, sessionId) => { + const eventRequest = endpointLogs.requests[0]; + await responseStatus(endpointLogs.requests, 204); + + const event = JSON.parse(eventRequest.request.body).events[0]; + await t.expect(event.xdm.mediaCollection.sessionID).eql(sessionId); + await t.expect(event.xdm.eventType).eql(eventType); +}; + +test("Test that MC component doesn't send pings automatically", async () => { + const alloy = createAlloyProxy(); + await alloy.configure(config); + const { sessionId } = await assertSessionStarted(alloy); + // play event + await sendMediaEvent(alloy, "media.play", sessionId); + await assertEventIsSent( + networkLogger.mediaPlayEndpointLogs, + "media.play", + sessionId, + ); + + // pause event + await sendMediaEvent(alloy, "media.pauseStart", sessionId); + await assertEventIsSent( + networkLogger.mediaPauseEndpointLogs, + "media.pauseStart", + sessionId, + ); + + // chapter start event + await sendMediaEvent(alloy, "media.chapterStart", sessionId, { + chapterDetails: { + friendlyName: "Chapter 1", + length: 10, + index: 1, + offset: 0, + }, + }); + await assertEventIsSent( + networkLogger.chapterStartEndpointLogs, + "media.chapterStart", + sessionId, + ); + + // chapter complete event + await sendMediaEvent(alloy, "media.chapterComplete", sessionId); + await assertEventIsSent( + networkLogger.chapterCompleteEndpointLogs, + "media.chapterComplete", + sessionId, + ); + + // chapter skip event + await sendMediaEvent(alloy, "media.chapterSkip", sessionId); + await assertEventIsSent( + networkLogger.chapterSkipEndpointLogs, + "media.chapterSkip", + sessionId, + ); + + // ad break start event + await sendMediaEvent(alloy, "media.adBreakStart", sessionId, { + advertisingPodDetails: { + friendlyName: "Mid-roll", + offset: 0, + index: 1, + }, + }); + await assertEventIsSent( + networkLogger.adBreakStartEndpointLogs, + "media.adBreakStart", + sessionId, + ); + // ad start event + await sendMediaEvent(alloy, "media.adStart", sessionId, { + advertisingDetails: { + friendlyName: "Ad 1", + name: "/uri-reference/001", + length: 10, + advertiser: "Adobe Marketing", + campaignID: "Adobe Analytics", + creativeID: "creativeID", + creativeURL: "https://creativeurl.com", + placementID: "placementID", + siteID: "siteID", + podPosition: 11, + playerName: "HTML5 player", + }, + }); + await assertEventIsSent( + networkLogger.adStartEndpointLogs, + "media.adStart", + sessionId, + ); + + // ad complete event + await sendMediaEvent(alloy, "media.adComplete", sessionId); + await assertEventIsSent( + networkLogger.adCompleteEndpointLogs, + "media.adComplete", + sessionId, + ); + // ad break complete event + await sendMediaEvent(alloy, "media.adBreakComplete", sessionId); + await assertEventIsSent( + networkLogger.adBreakCompleteEndpointLogs, + "media.adBreakComplete", + sessionId, + ); + // ad skip event + await sendMediaEvent(alloy, "media.adSkip", sessionId); + await assertEventIsSent( + networkLogger.adSkipEndpointLogs, + "media.adSkip", + sessionId, + ); + // error event + await sendMediaEvent(alloy, "media.error", sessionId, { + errorDetails: { + name: "test-buffer-start", + source: "player", + }, + }); + await assertEventIsSent( + networkLogger.errorEndpointLogs, + "media.error", + sessionId, + ); + // bitrate change event + await sendMediaEvent(alloy, "media.bufferStart", sessionId); + await assertEventIsSent( + networkLogger.bufferStartEndpointLogs, + "media.bufferStart", + sessionId, + ); + // bitrate change event + await sendMediaEvent(alloy, "media.bitrateChange", sessionId, { + qoeDataDetails: { + framesPerSecond: 1, + bitrate: 35000, + droppedFrames: 30, + timeToStart: 1364, + }, + }); + await assertEventIsSent( + networkLogger.bitrateChangeEndpointLogs, + "media.bitrateChange", + sessionId, + ); + // states update event + await sendMediaEvent(alloy, "media.statesUpdate", sessionId, { + statesStart: [ + { + name: "mute", + }, + { + name: "pictureInPicture", + }, + ], + statesEnd: [ + { + name: "fullScreen", + }, + ], + }); + await assertEventIsSent( + networkLogger.statesUpdateEndpointLogs, + "media.statesUpdate", + sessionId, + ); + + await assertPingsNotSent(alloy); +}); diff --git a/packages/browser/test/functional/specs/Migration/C8085773.js b/packages/browser/test/functional/specs/Migration/C8085773.js new file mode 100644 index 000000000..f47b527d4 --- /dev/null +++ b/packages/browser/test/functional/specs/Migration/C8085773.js @@ -0,0 +1,104 @@ +/* +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 } from "testcafe"; +import createNetworkLogger from "../../helpers/networkLogger/index.js"; +import createFixture from "../../helpers/createFixture/index.js"; +import { + compose, + orgMainConfigMain, + debugEnabled, + targetMigrationEnabled, +} from "../../helpers/constants/configParts/index.js"; +import { TEST_PAGE, TEST_PAGE_AT_JS_ONE } from "../../helpers/constants/url.js"; +import { + MBOX_EDGE_CLUSTER, + MBOX, +} from "../../../../../core/src/constants/legacyCookies.js"; +import { + assertKonductorReturnsCookieAndCookieIsSet, + assertSameLocationHintIsUsed, + assertTargetMigrationEnabledIsSent, +} from "./helper.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; + +const networkLogger = createNetworkLogger(); +const config = compose(orgMainConfigMain, debugEnabled, targetMigrationEnabled); + +createFixture({ + title: + "C8085773: Web SDK to At.js 1.x - Assert same session ID, edge cluster are used for both of the requests " + + "interact and delivery API", + requestHooks: [ + networkLogger.edgeEndpointLogs, + networkLogger.targetMboxJsonEndpointLogs, + ], + url: TEST_PAGE, + includeAlloyLibrary: true, +}); + +test.meta({ + ID: "C8085773", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +test( + "C8085773: Web SDK to At.js 1.x - Assert same session ID, edge cluster are used for both of the requests " + + "interact and delivery API", + async () => { + // Loaded a page with Alloy + const alloy = createAlloyProxy(); + await alloy.configure(config); + await alloy.sendEvent(); + + const sendEventRequest = networkLogger.edgeEndpointLogs.requests[0]; + + // Check that targetMigrationEnabled flag is sent in meta + await assertTargetMigrationEnabledIsSent(sendEventRequest); + + // Check that mbox cookie is present in the response from Konductor + const mboxCookie = await assertKonductorReturnsCookieAndCookieIsSet( + MBOX, + sendEventRequest, + ); + + // Check that mboxEdgeCluster cookie is present in the response from Konductor + const mboxEdgeClusterCookie = + await assertKonductorReturnsCookieAndCookieIsSet( + MBOX_EDGE_CLUSTER, + sendEventRequest, + ); + + // NAVIGATE to clean page + await t.navigateTo(TEST_PAGE_AT_JS_ONE); + // get mbox json API request + await t + .expect(networkLogger.targetMboxJsonEndpointLogs.count(() => true)) + .eql(1); + const mboxJsonRequest = + networkLogger.targetMboxJsonEndpointLogs.requests[0]; + const requestUrl = mboxJsonRequest.request.url; + const { searchParams, hostname } = new URL(requestUrl); + + // assert session IDs are the same for both requests + const sessionIdFromMboxJsonRequest = searchParams.get("mboxSession"); + await t + .expect(mboxCookie) + .contains( + `#${sessionIdFromMboxJsonRequest}#`, + "Session ID returned from Target Upstream does not match the session ID sent in the request to Target", + ); + + // assert the same cluster is used + await assertSameLocationHintIsUsed(hostname, mboxEdgeClusterCookie); + }, +); diff --git a/packages/browser/test/functional/specs/Migration/C8085774.js b/packages/browser/test/functional/specs/Migration/C8085774.js new file mode 100644 index 000000000..40a13fcf0 --- /dev/null +++ b/packages/browser/test/functional/specs/Migration/C8085774.js @@ -0,0 +1,103 @@ +/* +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 } from "testcafe"; +import createNetworkLogger from "../../helpers/networkLogger/index.js"; +import createFixture from "../../helpers/createFixture/index.js"; +import { + compose, + orgMainConfigMain, + debugEnabled, + targetMigrationEnabled, +} from "../../helpers/constants/configParts/index.js"; +import { TEST_PAGE, TEST_PAGE_AT_JS_TWO } from "../../helpers/constants/url.js"; +import { + MBOX_EDGE_CLUSTER, + MBOX, +} from "../../../../../core/src/constants/legacyCookies.js"; +import { + assertKonductorReturnsCookieAndCookieIsSet, + assertSameLocationHintIsUsed, + assertTargetMigrationEnabledIsSent, +} from "./helper.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; + +const networkLogger = createNetworkLogger(); +const config = compose(orgMainConfigMain, debugEnabled, targetMigrationEnabled); + +createFixture({ + title: + "C8085774: Web SDK to At.js 2.x - Assert same session ID, edge cluster are used for " + + "both of the requests interact and delivery API", + requestHooks: [ + networkLogger.edgeEndpointLogs, + networkLogger.targetDeliveryEndpointLogs, + ], + url: TEST_PAGE, + includeAlloyLibrary: true, +}); + +test.meta({ + ID: "C8085774", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +test( + "C8085774: Web SDK to At.js 2.x - Assert same session ID, edge cluster are used for both of the " + + "requests interact and delivery API", + async () => { + // Loaded a page with Alloy + const alloy = createAlloyProxy(); + await alloy.configure(config); + await alloy.sendEvent(); + + const sendEventRequest = networkLogger.edgeEndpointLogs.requests[0]; + + // Check that targetMigrationEnabled flag is sent in meta + await assertTargetMigrationEnabledIsSent(sendEventRequest); + // Check that mbox cookie is present in the response from Konductor + const mboxCookie = await assertKonductorReturnsCookieAndCookieIsSet( + MBOX, + sendEventRequest, + ); + + // Check that mboxEdgeCluster cookie is present in the response from Konductor + const mboxEdgeClusterCookie = + await assertKonductorReturnsCookieAndCookieIsSet( + MBOX_EDGE_CLUSTER, + sendEventRequest, + ); + + // NAVIGATE to clean page + await t.navigateTo(TEST_PAGE_AT_JS_TWO); + // get delivery API request adding sleep to make sure the request was triggered + await t + .expect(networkLogger.targetDeliveryEndpointLogs.count(() => true)) + .eql(1); + const deliveryRequest = + networkLogger.targetDeliveryEndpointLogs.requests[0]; + const requestUrl = deliveryRequest.request.url; + const { searchParams, hostname } = new URL(requestUrl); + + // assert session IDs are the same for both requests + const sessionIdFromDeliveryRequest = searchParams.get("sessionId"); + await t + .expect(mboxCookie) + .contains( + `#${sessionIdFromDeliveryRequest}#`, + "Session ID returned from Target Upstream does not match the session ID sent to delivery API", + ); + + // assert the same cluster is used + await assertSameLocationHintIsUsed(hostname, mboxEdgeClusterCookie); + }, +); diff --git a/packages/browser/test/functional/specs/Migration/C8085775.js b/packages/browser/test/functional/specs/Migration/C8085775.js new file mode 100644 index 000000000..254a0df4b --- /dev/null +++ b/packages/browser/test/functional/specs/Migration/C8085775.js @@ -0,0 +1,102 @@ +/* +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 } from "testcafe"; +import createNetworkLogger from "../../helpers/networkLogger/index.js"; +import createFixture from "../../helpers/createFixture/index.js"; +import { + compose, + orgMainConfigMain, + debugEnabled, + targetMigrationEnabled, +} from "../../helpers/constants/configParts/index.js"; +import { TEST_PAGE, TEST_PAGE_AT_JS_ONE } from "../../helpers/constants/url.js"; +import cookies from "../../helpers/cookies.js"; +import { + MBOX_EDGE_CLUSTER, + MBOX, +} from "../../../../../core/src/constants/legacyCookies.js"; +import { + assertTargetMigrationEnabledIsSent, + getLocationHint, + injectAlloyAndSendEvent, +} from "./helper.js"; +import { responseStatus } from "../../helpers/assertions/index.js"; + +const networkLogger = createNetworkLogger(); +const config = compose(orgMainConfigMain, debugEnabled, targetMigrationEnabled); + +createFixture({ + title: + "C8085775: At.js 1.x to Web SDK - Assert same session ID, edge cluster are " + + "used for both of the requests interact and delivery API", + requestHooks: [ + networkLogger.edgeEndpointLogs, + networkLogger.targetMboxJsonEndpointLogs, + ], + url: TEST_PAGE_AT_JS_ONE, + includeAlloyLibrary: false, +}); + +test.meta({ + ID: "C8085775", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +test( + "C8085775: At.js 1.x to Web SDK - Assert same session ID, edge cluster are " + + "used for both of the requests interact and delivery API", + async () => { + await t + .expect(networkLogger.targetMboxJsonEndpointLogs.count(() => true)) + .eql(1); + // Get mbox/json API request + const mboxJsonRequest = + networkLogger.targetMboxJsonEndpointLogs.requests[0]; + await responseStatus(networkLogger.targetMboxJsonEndpointLogs, [200, 207]); + const { searchParams } = new URL(mboxJsonRequest.request.url); + // Extract the session ID from the request query params + const sessionIdFromMboxJsonRequest = searchParams.get("mboxSession"); + const mboxEdgeClusterCookieValue = await cookies.get(MBOX_EDGE_CLUSTER); + await t.expect(mboxEdgeClusterCookieValue).ok(); + // Check that mbox cookie is set + const mboxCookieValue = await cookies.get(MBOX); + await t.expect(mboxCookieValue).ok(); + + // NAVIGATE to a web sdk page + await t.navigateTo(TEST_PAGE); + await injectAlloyAndSendEvent(config); + const sendEventRequest = networkLogger.edgeEndpointLogs.requests[0]; + const requestBody = JSON.parse(sendEventRequest.request.body); + + // Check that targetMigrationEnabled is sent in meta + await assertTargetMigrationEnabledIsSent(sendEventRequest); + // Extract location hint + const { pathname } = new URL(sendEventRequest.request.url); + const aepRequestLocationHint = getLocationHint(pathname); + // Assert the location hint used for interact endpoint is the same as in mboxEdgeCluster Cookie value + await t.expect(mboxEdgeClusterCookieValue).eql(aepRequestLocationHint); + // Check that mbox cookie is present in the request state + const { entries: stateStore } = requestBody.meta.state; + + const requestMboxCookie = stateStore.find((entry) => { + return entry.key.includes(MBOX); + }); + // Assert the session IDs are the same + await t + .expect(requestMboxCookie.value) + .contains( + `#${sessionIdFromMboxJsonRequest}#`, + "Session ID from request should be eql to session ID from mbox cookie sent in meta.state", + ); + }, +); diff --git a/packages/browser/test/functional/specs/Migration/C8085776.js b/packages/browser/test/functional/specs/Migration/C8085776.js new file mode 100644 index 000000000..fb1b5a290 --- /dev/null +++ b/packages/browser/test/functional/specs/Migration/C8085776.js @@ -0,0 +1,102 @@ +/* +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 } from "testcafe"; +import createNetworkLogger from "../../helpers/networkLogger/index.js"; +import createFixture from "../../helpers/createFixture/index.js"; +import { + compose, + orgMainConfigMain, + debugEnabled, + targetMigrationEnabled, +} from "../../helpers/constants/configParts/index.js"; +import { TEST_PAGE, TEST_PAGE_AT_JS_TWO } from "../../helpers/constants/url.js"; +import cookies from "../../helpers/cookies.js"; +import { + MBOX_EDGE_CLUSTER, + MBOX, +} from "../../../../../core/src/constants/legacyCookies.js"; +import { + assertTargetMigrationEnabledIsSent, + getLocationHint, + injectAlloyAndSendEvent, +} from "./helper.js"; +import { responseStatus } from "../../helpers/assertions/index.js"; + +const networkLogger = createNetworkLogger(); +const config = compose(orgMainConfigMain, debugEnabled, targetMigrationEnabled); + +createFixture({ + title: + "C8085776: At.js 2.x to Web SDK - Assert same session ID, edge cluster are used " + + "for both of the requests interact and delivery API", + requestHooks: [ + networkLogger.edgeEndpointLogs, + networkLogger.targetDeliveryEndpointLogs, + ], + url: TEST_PAGE_AT_JS_TWO, + includeAlloyLibrary: false, +}); + +test.meta({ + ID: "C8085776", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +test( + "C8085776: At.js 2.x to Web SDK - Assert same session ID, edge cluster are used " + + "for both of the requests interact and delivery API", + async () => { + await t + .expect(networkLogger.targetDeliveryEndpointLogs.count(() => true)) + .eql(1); + // Get delivery API request + const deliveryRequest = + networkLogger.targetDeliveryEndpointLogs.requests[0]; + await responseStatus(networkLogger.targetDeliveryEndpointLogs, [200, 207]); + const { searchParams } = new URL(deliveryRequest.request.url); + // Extract the session ID from the request query params + const sessionIdFromDeliveryRequest = searchParams.get("sessionId"); + const mboxEdgeClusterCookieValue = await cookies.get(MBOX_EDGE_CLUSTER); + await t.expect(mboxEdgeClusterCookieValue).ok(); + // Check that mbox cookie is set + const mboxCookieValue = await cookies.get(MBOX); + await t.expect(mboxCookieValue).ok(); + + // NAVIGATE to a web sdk page + await t.navigateTo(TEST_PAGE); + await injectAlloyAndSendEvent(config); + const sendEventRequest = networkLogger.edgeEndpointLogs.requests[0]; + const requestBody = JSON.parse(sendEventRequest.request.body); + + // Check that targetMigrationEnabled is sent in meta + await assertTargetMigrationEnabledIsSent(sendEventRequest); + // Extract location hint + const { pathname } = new URL(sendEventRequest.request.url); + const aepRequestLocationHint = getLocationHint(pathname); + // Assert the location hint used for interact endpoint is the same as in mboxEdgeCluster Cookie value + await t.expect(mboxEdgeClusterCookieValue).eql(aepRequestLocationHint); + // Check that mbox cookie is present in the request state + const { entries: stateStore } = requestBody.meta.state; + + const requestMboxCookie = stateStore.find((entry) => { + return entry.key.includes(MBOX); + }); + // Assert the session IDs are the same + await t + .expect(requestMboxCookie.value) + .contains( + `#${sessionIdFromDeliveryRequest}#`, + "Session ID from Delivery request should be eql to session ID from mbox cookie sent in meta.state", + ); + }, +); diff --git a/packages/browser/test/functional/specs/Migration/C8085777.js b/packages/browser/test/functional/specs/Migration/C8085777.js new file mode 100644 index 000000000..b062688f3 --- /dev/null +++ b/packages/browser/test/functional/specs/Migration/C8085777.js @@ -0,0 +1,133 @@ +/* +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 } from "testcafe"; +import createNetworkLogger from "../../helpers/networkLogger/index.js"; +import createFixture from "../../helpers/createFixture/index.js"; +import { + compose, + orgMainConfigMain, + debugEnabled, + targetMigrationEnabled, +} from "../../helpers/constants/configParts/index.js"; +import { TEST_PAGE, TEST_PAGE_AT_JS_TWO } from "../../helpers/constants/url.js"; +import getResponseBody from "../../helpers/networkLogger/getResponseBody.js"; +import { + MBOX_EDGE_CLUSTER, + MBOX, +} from "../../../../../core/src/constants/legacyCookies.js"; +import { + assertKonductorReturnsCookieAndCookieIsSet, + assertSameLocationHintIsUsed, + assertTargetMigrationEnabledIsSent, + fetchMboxOffer, + MIGRATION_LOCATION, +} from "./helper.js"; +import migrationEnabled from "../../helpers/constants/configParts/migrationEnabled.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; + +const favoriteColor = "violet-1234"; +const networkLogger = createNetworkLogger(); +const config = compose( + orgMainConfigMain, + debugEnabled, + migrationEnabled, + targetMigrationEnabled, +); +createFixture({ + title: + "C8085777: Use same visitor profile in mixed mode implementation: Update profile attribute using " + + "web sdk and fetch offer based on profile attr using at.js 2.x", + requestHooks: [ + networkLogger.edgeEndpointLogs, + networkLogger.targetDeliveryEndpointLogs, + ], + url: TEST_PAGE, + includeAlloyLibrary: true, +}); + +test.meta({ + ID: "C8085777", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +test.skip( + "C8085777: Use same visitor profile in mixed mode implementation: Update profile attribute using " + + "web sdk and fetch offer based on profile attr using at.js 2.x", + async () => { + const options = { + renderDecisions: true, + data: { + __adobe: { + target: { + "profile.favoriteColor": favoriteColor, + }, + }, + }, + }; + // Loaded a page with Alloy + const alloy = createAlloyProxy(); + await alloy.configure(config); + await alloy.sendEvent(options); + await t.expect(networkLogger.edgeEndpointLogs.count(() => true)).eql(1); + const sendEventRequest = networkLogger.edgeEndpointLogs.requests[0]; + + // Check that targetMigrationEnabled flag is sent in meta + await assertTargetMigrationEnabledIsSent(sendEventRequest); + + // Check that mbox cookie is present in the response from Konductor + const mboxCookie = await assertKonductorReturnsCookieAndCookieIsSet( + MBOX, + sendEventRequest, + ); + + // Check that mboxEdgeCluster cookie is present in the response from Konductor + const mboxEdgeClusterCookie = + await assertKonductorReturnsCookieAndCookieIsSet( + MBOX_EDGE_CLUSTER, + sendEventRequest, + ); + + // NAVIGATE to clean page + await t.navigateTo(TEST_PAGE_AT_JS_TWO); + // get delivery API request adding sleep to make sure the request was triggered + await fetchMboxOffer({ mbox: MIGRATION_LOCATION }); + const deliveryRequest = + networkLogger.targetDeliveryEndpointLogs.requests[1]; + await t + .expect(networkLogger.targetDeliveryEndpointLogs.count(() => true)) + .eql(2); + // Extract state:store payload + const deliveryResponse = JSON.parse(getResponseBody(deliveryRequest)); + + const mbox = deliveryResponse.execute.mboxes[0]; + + const content = mbox.options[0].content; + await t + .expect(content) + .eql(`The favorite Color for this visitor is ${favoriteColor}.`); + const requestUrl = deliveryRequest.request.url; + const { searchParams, hostname } = new URL(requestUrl); + + // assert session IDs are the same for both requests + const sessionIdFromDeliveryRequest = searchParams.get("sessionId"); + await t + .expect(mboxCookie) + .contains( + `#${sessionIdFromDeliveryRequest}#`, + "Session ID returned from Target Upstream does not match the session ID sent to delivery API", + ); + + // assert the same cluster is used + await assertSameLocationHintIsUsed(hostname, mboxEdgeClusterCookie); + }, +); diff --git a/packages/browser/test/functional/specs/Migration/C8085778.js b/packages/browser/test/functional/specs/Migration/C8085778.js new file mode 100644 index 000000000..bdebae878 --- /dev/null +++ b/packages/browser/test/functional/specs/Migration/C8085778.js @@ -0,0 +1,120 @@ +/* +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 } from "testcafe"; +import createNetworkLogger from "../../helpers/networkLogger/index.js"; +import createFixture from "../../helpers/createFixture/index.js"; +import { + compose, + orgMainConfigMain, + debugEnabled, + targetMigrationEnabled, +} from "../../helpers/constants/configParts/index.js"; +import { TEST_PAGE, TEST_PAGE_AT_JS_ONE } from "../../helpers/constants/url.js"; +import getResponseBody from "../../helpers/networkLogger/getResponseBody.js"; +import { + assertTargetMigrationEnabledIsSent, + fetchMboxOffer, + getEcid, + MIGRATION_LOCATION, + sleep, +} from "./helper.js"; +import migrationEnabled from "../../helpers/constants/configParts/migrationEnabled.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; +import createResponse from "../../helpers/createResponse.js"; + +const favoriteColor = "purple-123"; +const networkLogger = createNetworkLogger(); + +const config = compose( + orgMainConfigMain, + debugEnabled, + migrationEnabled, + targetMigrationEnabled, +); + +createFixture({ + title: + "C8085778: Use same visitor profile in mixed mode implementation - Update profile attribute " + + "using web sdk and fetch offer based on profile attr using at.js 1.x", + requestHooks: [ + networkLogger.edgeEndpointLogs, + networkLogger.targetMboxJsonEndpointLogs, + ], + url: TEST_PAGE, + includeAlloyLibrary: true, +}); + +test.meta({ + ID: "C8085778", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +test.skip( + "C8085778: Use same visitor profile in mixed mode implementation - Update profile attribute " + + "using web sdk and fetch offer based on profile attr using at.js 1.x", + async () => { + const options = { + renderDecisions: true, + data: { + __adobe: { + target: { + "profile.favoriteColor": favoriteColor, + }, + }, + }, + }; + const alloy = createAlloyProxy(); + await alloy.configure(config); + await alloy.sendEvent(options); + await sleep(3000); + const sendEventRequest = networkLogger.edgeEndpointLogs.requests[0]; + // Check that targetMigrationEnabled flag is sent in meta + await assertTargetMigrationEnabledIsSent(sendEventRequest); + + // Extract state:store payload + const response = JSON.parse( + getResponseBody(networkLogger.edgeEndpointLogs.requests[0]), + ); + + const identityPayload = createResponse({ + content: response, + }).getPayloadsByType("identity:result"); + const ecid = getEcid(identityPayload)[0].id; + + // NAVIGATE to clean page + await t.navigateTo(TEST_PAGE_AT_JS_ONE); + // get mbox json API request + await t + .expect(networkLogger.targetMboxJsonEndpointLogs.count(() => true)) + .eql(1); + await fetchMboxOffer({ + mbox: MIGRATION_LOCATION, + }); + await t + .expect(networkLogger.targetMboxJsonEndpointLogs.count(() => true)) + .eql(2); + const customMboxJsonRequest = + networkLogger.targetMboxJsonEndpointLogs.requests[1]; + const mboxRequestUrlQuery = new URL(customMboxJsonRequest.request.url) + .searchParams; + const ecidMboxJsonRequest = mboxRequestUrlQuery.get("mboxMCGVID"); + // assert both interact and mbox json requests are sending the same identity + await t.expect(ecid).eql(ecidMboxJsonRequest); + const mboxJsonResponse = JSON.parse(getResponseBody(customMboxJsonRequest)); + const mboxContent = mboxJsonResponse.offers[0].html; + + await t + .expect(mboxContent) + .eql(`The favorite Color for this visitor is ${favoriteColor}.`); + }, +); diff --git a/packages/browser/test/functional/specs/Migration/C8085779.js b/packages/browser/test/functional/specs/Migration/C8085779.js new file mode 100644 index 000000000..8c4ed4eeb --- /dev/null +++ b/packages/browser/test/functional/specs/Migration/C8085779.js @@ -0,0 +1,108 @@ +/* +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 } from "testcafe"; +import createNetworkLogger from "../../helpers/networkLogger/index.js"; +import createFixture from "../../helpers/createFixture/index.js"; +import { + compose, + orgMainConfigMain, + debugEnabled, + targetMigrationEnabled, +} from "../../helpers/constants/configParts/index.js"; +import { TEST_PAGE, TEST_PAGE_AT_JS_ONE } from "../../helpers/constants/url.js"; +import { + fetchMboxOffer, + getEcid, + getPropositionCustomContent, + injectAlloyAndSendEvent, + MIGRATION_LOCATION, +} from "./helper.js"; +import getResponseBody from "../../helpers/networkLogger/getResponseBody.js"; +import createResponse from "../../helpers/createResponse.js"; +import migrationEnabled from "../../helpers/constants/configParts/migrationEnabled.js"; +import { responseStatus } from "../../helpers/assertions/index.js"; + +const favoriteColor = "green-1234"; +const networkLogger = createNetworkLogger(); + +const config = compose( + orgMainConfigMain, + debugEnabled, + migrationEnabled, + targetMigrationEnabled, +); + +createFixture({ + title: + "C8085779: Use same visitor profile in mixed mode implementation: Update profile attribute using " + + "at.js 1.x and fetch proposition offer based on profile attr using web sdk", + requestHooks: [ + networkLogger.edgeEndpointLogs, + networkLogger.targetMboxJsonEndpointLogs, + ], + url: TEST_PAGE_AT_JS_ONE, + includeAlloyLibrary: false, +}); + +test.meta({ + ID: "C8085779", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +test( + "C8085779: Use same visitor profile in mixed mode implementation: Update profile attribute using " + + "at.js 1.x and fetch proposition offer based on profile attr using web sdk", + async () => { + // delivery API request + await fetchMboxOffer({ + params: { + "profile.favoriteColor": favoriteColor, + }, + }); + await t + .expect(networkLogger.targetMboxJsonEndpointLogs.count(() => true)) + .eql(2); + const mboxJsonRequest = + networkLogger.targetMboxJsonEndpointLogs.requests[1]; + await responseStatus(networkLogger.targetMboxJsonEndpointLogs, [200, 207]); + const mboxRequestUrlQuery = new URL(mboxJsonRequest.request.url) + .searchParams; + const marketingCloudVisitorId = mboxRequestUrlQuery.get("mboxMCGVID"); + + // NAVIGATE to a web sdk page + await t.navigateTo(TEST_PAGE); + await injectAlloyAndSendEvent(config, { + decisionScopes: [MIGRATION_LOCATION], + }); + const sendEventRequest = networkLogger.edgeEndpointLogs.requests[0]; + const response = JSON.parse(getResponseBody(sendEventRequest)); + const identityPayload = createResponse({ + content: response, + }).getPayloadsByType("identity:result"); + const ecid = getEcid(identityPayload)[0].id; + + // expect same ecid is used in both requests + await t.expect(marketingCloudVisitorId).eql(ecid); + const personalizationPayload = createResponse({ + content: response, + }).getPayloadsByType("personalization:decisions"); + + const propositionCustomContent = getPropositionCustomContent( + personalizationPayload, + ); + // expect to get a offer based on the profile attr updated in the previous call using legacy libs + await t + .expect(propositionCustomContent) + .eql(`The favorite Color for this visitor is ${favoriteColor}.`); + }, +); diff --git a/packages/browser/test/functional/specs/Migration/C8085780.js b/packages/browser/test/functional/specs/Migration/C8085780.js new file mode 100644 index 000000000..83ce80204 --- /dev/null +++ b/packages/browser/test/functional/specs/Migration/C8085780.js @@ -0,0 +1,104 @@ +/* +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 } from "testcafe"; +import createNetworkLogger from "../../helpers/networkLogger/index.js"; +import createFixture from "../../helpers/createFixture/index.js"; +import { + compose, + orgMainConfigMain, + debugEnabled, + targetMigrationEnabled, +} from "../../helpers/constants/configParts/index.js"; +import { TEST_PAGE, TEST_PAGE_AT_JS_TWO } from "../../helpers/constants/url.js"; +import { + fetchMboxOffer, + getPropositionCustomContent, + injectAlloyAndSendEvent, + MIGRATION_LOCATION, +} from "./helper.js"; +import getResponseBody from "../../helpers/networkLogger/getResponseBody.js"; +import createResponse from "../../helpers/createResponse.js"; +import migrationEnabled from "../../helpers/constants/configParts/migrationEnabled.js"; +import { responseStatus } from "../../helpers/assertions/index.js"; + +const favoriteColor = "red-1234"; + +const networkLogger = createNetworkLogger(); +const config = compose( + orgMainConfigMain, + debugEnabled, + migrationEnabled, + targetMigrationEnabled, +); + +createFixture({ + title: + "C8085780: Use same visitor profile in mixed mode implementation - Update profile attribute " + + "using at.js 2.x and fetch proposition offer based on profile attr using web sdk", + requestHooks: [ + networkLogger.edgeEndpointLogs, + networkLogger.targetDeliveryEndpointLogs, + ], + url: TEST_PAGE_AT_JS_TWO, + includeAlloyLibrary: false, +}); + +test.meta({ + ID: "C8085780", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +test( + "C8085780: Use same visitor profile in mixed mode implementation - Update profile attribute " + + "using at.js 2.x and fetch proposition offer based on profile attr using web sdk", + async () => { + // delivery API request + await fetchMboxOffer({ + params: { + "profile.favoriteColor": favoriteColor, + }, + }); + await t + .expect(networkLogger.targetDeliveryEndpointLogs.count(() => true)) + .eql(2); + const deliveryRequest = + networkLogger.targetDeliveryEndpointLogs.requests[1]; + await responseStatus(networkLogger.targetDeliveryEndpointLogs, [200, 207]); + const requestBody = JSON.parse(deliveryRequest.request.body); + const { marketingCloudVisitorId } = requestBody.id; + + // NAVIGATE to a web sdk page + await t.navigateTo(TEST_PAGE); + await injectAlloyAndSendEvent(config, { + decisionScopes: [MIGRATION_LOCATION], + }); + const sendEventRequest = networkLogger.edgeEndpointLogs.requests[0]; + const response = JSON.parse(getResponseBody(sendEventRequest)); + const identityRequestBody = JSON.parse(sendEventRequest.request.body); + const ecid = identityRequestBody.xdm.identityMap.ECID[0].id; + + // expect same ecid is used in both requests + await t.expect(marketingCloudVisitorId).eql(ecid); + const personalizationPayload = createResponse({ + content: response, + }).getPayloadsByType("personalization:decisions"); + + const propositionCustomContent = getPropositionCustomContent( + personalizationPayload, + ); + // expect to get a offer based on the profile attr updated in the previous call using legacy libs + await t + .expect(propositionCustomContent) + .eql(`The favorite Color for this visitor is ${favoriteColor}.`); + }, +); diff --git a/packages/browser/test/functional/specs/Migration/helper.js b/packages/browser/test/functional/specs/Migration/helper.js new file mode 100644 index 000000000..1e0e9d16b --- /dev/null +++ b/packages/browser/test/functional/specs/Migration/helper.js @@ -0,0 +1,113 @@ +/* +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 { ClientFunction, t } from "testcafe"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; +import createConsoleLogger from "../../helpers/consoleLogger/index.js"; +import { injectAlloyDuringTest } from "../../helpers/createFixture/clientScripts.js"; +import cookies from "../../helpers/cookies.js"; +import getResponseBody from "../../helpers/networkLogger/getResponseBody.js"; +import createResponse from "../../helpers/createResponse.js"; + +export const MIGRATION_LOCATION = "location-for-migration-testing"; +export const sleep = (ms) => + new Promise((resolve) => { + setTimeout(resolve, ms); + }); + +export const extractCluster = (hostname) => { + const values = hostname.split("."); + return values[0]; +}; + +export const injectAlloyAndSendEvent = async (config, options = {}) => { + const alloy = createAlloyProxy(); + await alloy.configureAsync(config); + await alloy.getLibraryInfoAsync(); + const logger = await createConsoleLogger(); + await injectAlloyDuringTest(); + await logger.info.expectMessageMatching(/Executing getLibraryInfo command/); + await alloy.sendEvent(options); +}; + +export const assertTargetMigrationEnabledIsSent = async (sendEventRequest) => { + const requestBody = JSON.parse(sendEventRequest.request.body); + + await t.expect(requestBody.meta.target).eql({ migration: true }); +}; + +export const assertKonductorReturnsCookieAndCookieIsSet = async ( + cookieKey, + sendEventRequest, +) => { + // Extract state:store payload + const response = JSON.parse(getResponseBody(sendEventRequest)); + const stateStorePayload = createResponse({ + content: response, + }).getPayloadsByType("state:store"); + await t.expect(stateStorePayload.length).gte(0); + + const responseContainsCookie = stateStorePayload.find((entry) => { + return entry.key.includes(cookieKey); + }); + await t.expect(responseContainsCookie).ok(); + // Check that cookie is set + const cookieValue = await cookies.get(cookieKey); + await t.expect(cookieValue).ok(); + + return cookieValue; +}; + +export const getLocationHint = (pathname) => { + const values = pathname.split("/"); + const locationHint = values[2]; + + return Number(locationHint.split("t")[1]); +}; + +export const getEcid = (identityPayload) => { + return identityPayload.filter((obj) => obj.namespace.code === "ECID"); +}; + +export const getPropositionCustomContent = (personalizationPayload) => { + const decisionScopeProposition = personalizationPayload.filter( + (proposition) => proposition.scope === MIGRATION_LOCATION, + ); + + return decisionScopeProposition[0].items[0].data.content; +}; + +export const fetchMboxOffer = ClientFunction( + ({ params = {}, mbox = "target-global-mbox" }) => { + return window.adobe.target.getOffer({ + mbox, + params, + success(response) { + return response; + }, + // eslint-disable-next-line no-console + error: console.error, + }); + }, +); + +export const assertSameLocationHintIsUsed = async ( + hostname, + mboxEdgeClusterCookie, +) => { + const cluster = await extractCluster(hostname); + await t + .expect(`mboxedge${mboxEdgeClusterCookie}`) + .eql( + cluster, + "Cluster ID returned from Target Upstream does not match the cluster ID used in the path to Target Edge API", + ); +}; diff --git a/packages/browser/test/functional/specs/Personalization/C11389844.js b/packages/browser/test/functional/specs/Personalization/C11389844.js new file mode 100644 index 000000000..8bd707344 --- /dev/null +++ b/packages/browser/test/functional/specs/Personalization/C11389844.js @@ -0,0 +1,191 @@ +/* +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 createNetworkLogger from "../../helpers/networkLogger/index.js"; +import { responseStatus } from "../../helpers/assertions/index.js"; +import createFixture from "../../helpers/createFixture/index.js"; +import addHtmlToBody from "../../helpers/dom/addHtmlToBody.js"; +import { + compose, + orgMainConfigMain, + debugEnabled, + thirdPartyCookiesDisabled, + ajoConfigForStage, +} from "../../helpers/constants/configParts/index.js"; +import getResponseBody from "../../helpers/networkLogger/getResponseBody.js"; +import createResponse from "../../helpers/createResponse.js"; +import { TEST_PAGE_WITH_CSP } from "../../helpers/constants/url.js"; +import flushPromiseChains from "../../helpers/flushPromiseChains.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; + +const networkLogger = createNetworkLogger(); +const config = compose( + orgMainConfigMain, + ajoConfigForStage, + debugEnabled, + thirdPartyCookiesDisabled, +); +const AJO_TEST_SURFACE = "web://alloyio.com/personalizationAjoSpa"; + +createFixture({ + title: "C11389844: AJO SPA support", + url: `${TEST_PAGE_WITH_CSP}?test=C11389844`, + requestHooks: [networkLogger.edgeEndpointLogs], +}); + +test.meta({ + ID: "C11389844", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +const getDecisionContent = ClientFunction((elementId) => { + const container = document.getElementById(elementId); + + return container.innerText; +}); + +const getDecisionsMetaByScope = (decisions, scope) => { + const metas = []; + + decisions.forEach((decision) => { + if (decision.scope === scope) { + metas.push({ + id: decision.id, + scope: decision.scope, + scopeDetails: decision.scopeDetails, + }); + } + }); + return metas; +}; + +const addContentContainer = () => { + return addHtmlToBody( + `
+ This is the AJO personalization placeholder for the products view. + Personalized content has not been loaded. +
`, + ); +}; + +const simulatePageLoad = async (alloy) => { + const personalization = { surfaces: [AJO_TEST_SURFACE] }; + + await alloy.sendEvent({ + renderDecisions: true, + personalization, + }); + + // asserts the request fired to Experience Edge has the expected event query + await responseStatus(networkLogger.edgeEndpointLogs.requests, [200, 207]); + + const sendEventRequest = networkLogger.edgeEndpointLogs.requests[0]; + const requestBody = JSON.parse(sendEventRequest.request.body); + const surfaces = requestBody.events[0].query.personalization.surfaces; + const hasSurfaces = surfaces.includes(AJO_TEST_SURFACE); + + await t.expect(hasSurfaces).eql(true); + + const personalizationSchemas = + requestBody.events[0].query.personalization.schemas; + + const result = [ + "https://ns.adobe.com/personalization/default-content-item", + "https://ns.adobe.com/personalization/dom-action", + "https://ns.adobe.com/personalization/html-content-item", + "https://ns.adobe.com/personalization/json-content-item", + "https://ns.adobe.com/personalization/redirect-item", + ].every((schema) => personalizationSchemas.includes(schema)); + + await t.expect(result).eql(true); + + const response = JSON.parse( + getResponseBody(networkLogger.edgeEndpointLogs.requests[0]), + ); + const personalizationPayload = createResponse({ + content: response, + }).getPayloadsByType("personalization:decisions"); + + await t.expect(personalizationPayload.length).eql(1); + await flushPromiseChains(); + + return personalizationPayload; +}; + +const simulateViewChange = async (alloy, personalizationPayload) => { + // sendEvent at a view change, this shouldn't request any data, it should use the existing cache + const resultingObject = await alloy.sendEvent({ + renderDecisions: true, + xdm: { + web: { + webPageDetails: { + viewName: "products", + }, + }, + }, + }); + + const viewChangeRequest = networkLogger.edgeEndpointLogs.requests[1]; + const viewChangeRequestBody = JSON.parse(viewChangeRequest.request.body); + const event = viewChangeRequestBody.events[0]; + const query = event.query; + const web = event.xdm.web; + // eslint-disable-next-line no-underscore-dangle + const experience = event.xdm._experience; + + // assert that no personalization query was attached to the request + await t.expect(query).eql(undefined); + // assert that no personalization query was attached to the request + await t.expect(web.webPageDetails.viewName).eql("products"); + + await t + .expect(getDecisionContent("personalization-products-container-ajo")) + .eql("Welcome to AJO SPA products!"); + + // Let promises resolve so that the notification is sent. + await flushPromiseChains(); + + // check that the view change request payload contains + // the decisions that were rendered + const productsViewDecisionsMeta = getDecisionsMetaByScope( + personalizationPayload, + "products", + ); + + await t + .expect(experience.decisioning.propositions) + .eql(productsViewDecisionsMeta); + await t.expect(experience.decisioning.propositionEventType.display).eql(1); + + // assert we return the renderAttempted flag set to true + const allPropositionsWereRendered = resultingObject.propositions.every( + (proposition) => proposition.renderAttempted, + ); + + await t.expect(allPropositionsWereRendered).eql(true); +}; + +test.skip("Test C11389844: AJO SPA support", async () => { + const alloy = createAlloyProxy(); + + await alloy.configure(config); + await addContentContainer(); + + const personalizationPayload = await simulatePageLoad(alloy); + + await simulateViewChange(alloy, personalizationPayload); +}); diff --git a/packages/browser/test/functional/specs/Personalization/C1234567.js b/packages/browser/test/functional/specs/Personalization/C1234567.js new file mode 100644 index 000000000..ed9309be1 --- /dev/null +++ b/packages/browser/test/functional/specs/Personalization/C1234567.js @@ -0,0 +1,711 @@ +/* eslint-disable func-style, prefer-object-spread */ +/* +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 { ClientFunction, t, Selector } from "testcafe"; +import uuid from "../../../../../core/src/utils/uuid.js"; +import createNetworkLogger from "../../helpers/networkLogger/index.js"; +import createFixture from "../../helpers/createFixture/index.js"; +import { + compose, + debugEnabled, +} from "../../helpers/constants/configParts/index.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; +import getBaseConfig from "../../helpers/getBaseConfig.js"; +import { TEST_PAGE as TEST_PAGE_URL } from "../../helpers/constants/url.js"; +import addHtmlToBody from "../../helpers/dom/addHtmlToBody.js"; +import { ADOBE_JOURNEY_OPTIMIZER } from "../../../../../core/src/constants/decisionProvider.js"; +import { responseStatus } from "../../helpers/assertions/index.js"; +import flushPromiseChains from "../../helpers/flushPromiseChains.js"; + +const REASONABLE_WAIT_TIME = 250; + +const networkLogger = createNetworkLogger(); +const { edgeEndpointLogs } = networkLogger; + +const orgId = "97D1F3F459CE0AD80A495CBE@AdobeOrg"; + +const orgMainConfigMain = getBaseConfig( + orgId, + "0a106b4d-1937-4196-a64d-4a324e972459", +); +const config = compose(orgMainConfigMain, debugEnabled, { + personalizationStorageEnabled: true, +}); + +test.meta({ + ID: "C1234567", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +createFixture({ + title: "C1234567 - Content Cards", + url: `${TEST_PAGE_URL}?test=C17409728`, + requestHooks: [edgeEndpointLogs], +}); + +const testPageBody = ` +

Content Cards

+
    +`; + +const createMockResponse = ({ + scope = "web://aepdemo.com/", + propositionId = uuid(), + activityId = uuid(), + decisionProvider = ADOBE_JOURNEY_OPTIMIZER, + items = [], +}) => { + return { + requestId: uuid(), + handle: [ + { + payload: [ + { + id: "54671057599843051332294448941462242513", + namespace: { + code: "ECID", + }, + }, + ], + type: "identity:result", + }, + { + payload: [ + { + id: propositionId, + scope, + scopeDetails: { + decisionProvider, + correlationID: "6dae465b-9553-4fc6-b7d4-6c9979c88f21-0", + characteristics: { + eventToken: + "eyJtZXNzYWdlRXhlY3V0aW9uIjp7Im1lc3NhZ2VFeGVjdXRpb25JRCI6IlVFOkluYm91bmQiLCJtZXNzYWdlSUQiOiJmMzgxZWJhYS1kNDIyLTQxNzQtOWUzNS0yMTY3NDYwMjk5MTAiLCJtZXNzYWdlUHVibGljYXRpb25JRCI6IjZkYWU0NjViLTk1NTMtNGZjNi1iN2Q0LTZjOTk3OWM4OGYyMSIsIm1lc3NhZ2VUeXBlIjoibWFya2V0aW5nIiwiY2FtcGFpZ25JRCI6ImVhZDg5MWE0LTNjYWUtNGE1ZC05MGEzLTFkZTc0MzkwYjNkMyIsImNhbXBhaWduVmVyc2lvbklEIjoiZDhiYzk5YmMtZGRhZC00Y2MyLThlYjItYTJlMGUzY2FmNzg0IiwiY2FtcGFpZ25BY3Rpb25JRCI6IjQzNmZmM2NkLTZkZWItNDczNi04NDc1LTA3NDhhYzc4MTlkOCJ9LCJtZXNzYWdlUHJvZmlsZSI6eyJtZXNzYWdlUHJvZmlsZUlEIjoiMDg5NGYwNmYtOTkyNi00YTc2LTk4OTktYThmZjc3NWZmNTA4IiwiY2hhbm5lbCI6eyJfaWQiOiJodHRwczovL25zLmFkb2JlLmNvbS94ZG0vY2hhbm5lbHMvd2ViIiwiX3R5cGUiOiJodHRwczovL25zLmFkb2JlLmNvbS94ZG0vY2hhbm5lbC10eXBlcy93ZWIifX19", + }, + activity: { + id: activityId, + }, + }, + items: [...items], + }, + ], + type: "personalization:decisions", + eventIndex: 0, + }, + ], + }; +}; + +const getHistoricEventFromLocalStorage = ClientFunction( + (organizationId, activityId, eventType) => { + const key = `com.adobe.alloy.${organizationId.split("@")[0]}_AdobeOrg.decisioning.events`; + const data = JSON.parse(localStorage.getItem(key) || "{}"); + const events = data[eventType] || {}; + const event = events[activityId]; + return event || null; + }, +); + +test("Test C1234567: Subscribes content cards", async () => { + const surface = "web://mywebsite.com/#my-cards"; + + const mockPublishedDate = Math.ceil(new Date().getTime() / 1000) - 864000; + const mockExpiryDate = Math.ceil(new Date().getTime() / 1000) + 864000; + + const activityId = uuid(); + const propositionId = uuid(); + const itemId = uuid(); + + const responseBody = createMockResponse({ + scope: surface, + activityId, + propositionId, + items: [ + { + id: itemId, + schema: "https://ns.adobe.com/personalization/ruleset-item", + data: { + version: 1, + rules: [ + { + condition: { + definition: { + conditions: [ + { + definition: { + key: "~timestampu", + matcher: "le", + values: [mockExpiryDate], + }, + type: "matcher", + }, + { + definition: { + conditions: [ + { + definition: { + events: [ + { + "iam.eventType": "trigger", + "iam.id": activityId, + }, + ], + matcher: "ge", + value: 1, + }, + type: "historical", + }, + { + definition: { + conditions: [ + { + definition: { + key: "action", + matcher: "eq", + values: ["deposit-funds"], + }, + type: "matcher", + }, + ], + logic: "and", + }, + type: "group", + }, + ], + logic: "or", + }, + type: "group", + }, + ], + logic: "and", + }, + type: "group", + }, + consequences: [ + { + type: "schema", + detail: { + schema: + "https://ns.adobe.com/personalization/message/content-card", + data: { + expiryDate: mockExpiryDate, + publishedDate: mockPublishedDate, + meta: { + surface, + }, + content: { + shouldPinToTop: false, + imageUrl: + "https://raw.githubusercontent.com/jasonwaters/assets/master/2024/05/img_20240523_1716483354.png", + actionTitle: "View balance", + actionUrl: "https://paypal.com", + body: "Now you're ready to earn!", + title: "Funds deposited.", + }, + contentType: "application/json", + }, + id: itemId, + }, + id: itemId, + }, + ], + }, + ], + }, + }, + ], + }); + + await addHtmlToBody(testPageBody, true); + + const alloy = createAlloyProxy(); + await alloy.configure(config); + await alloy.applyResponse({ + renderDecisions: true, + responseBody, + }); + + await alloy.subscribeRulesetItems({ + surfaces: [surface], + schemas: ["https://ns.adobe.com/personalization/message/content-card"], + callback: (result, collectEvent) => { + function createContentCard(proposition, item) { + const { data = {} } = item; + const { + content = {}, + meta = {}, + publishedDate, + qualifiedDate, + displayedDate, + } = data; + + return Object.assign({}, content, { + meta, + qualifiedDate, + displayedDate, + publishedDate, + getProposition: () => proposition, + }); + } + + function extractContentCards(propositions) { + return propositions + .reduce((allItems, proposition) => { + const { items = [] } = proposition; + + return allItems.concat( + items.map((item) => createContentCard(proposition, item)), + ); + }, []) + .sort( + (a, b) => + b.qualifiedDate - a.qualifiedDate || + b.publishedDate - a.publishedDate, + ); + } + + const { propositions = [] } = result; + + if (propositions.length === 0) { + return; + } + + const contentCards = extractContentCards(propositions); + + const ul = document.getElementById("content-cards"); + let html = ""; + contentCards.forEach((contentCard, idx) => { + html += `
  • Item Image
    ${contentCard.title}

    ${contentCard.body}

  • `; + }); + ul.innerHTML = html; + + collectEvent("display", propositions); + + ul.addEventListener("click", (evt) => { + const li = evt.target.closest("li"); + if (!li) { + return; + } + collectEvent("interact", [ + contentCards[li.dataset.idx].getProposition(), + ]); + }); + }, + }); + + await alloy.evaluateRulesets({ + renderDecisions: true, + personalization: { + decisionContext: { + action: "deposit-funds", + }, + }, + }); + + // allow async storage of event-history operations to complete + await flushPromiseChains(); + + // validate display event sent (network-level assertion) + await responseStatus(edgeEndpointLogs.requests, [200, 204, 207]); + await flushPromiseChains(); + await t.expect(edgeEndpointLogs.count(() => true)).eql(1); + const displayRequest = edgeEndpointLogs.requests[0]; + const displayBody = JSON.parse(displayRequest.request.body); + await t + .expect(displayBody.events[0].xdm.eventType) + .eql("decisioning.propositionDisplay"); + await t + .expect( + // eslint-disable-next-line no-underscore-dangle + displayBody.events[0].xdm._experience.decisioning.propositions.length, + ) + .gt(0); + + await t.click("#content-card-0"); + await t.wait(REASONABLE_WAIT_TIME); + + await flushPromiseChains(); + + // validate interact event sent (network-level assertion) + await responseStatus(edgeEndpointLogs.requests, [200, 204, 207]); + await flushPromiseChains(); + const interactRequest = edgeEndpointLogs.requests[1]; + const interactBody = JSON.parse(interactRequest.request.body); + await t + .expect(interactBody.events[0].xdm.eventType) + .eql("decisioning.propositionInteract"); + await t + .expect( + // eslint-disable-next-line no-underscore-dangle + interactBody.events[0].xdm._experience.decisioning.propositions.length, + ) + .gt(0); + + // validate total requests + await t.expect(edgeEndpointLogs.count(() => true)).eql(2); +}); + +test("Test C1234567: Content card expiration", async () => { + const surface = "web://mywebsite.com/#expired-cards"; + + const mockPublishedDate = Math.ceil(new Date().getTime() / 1000) - 864000; + const mockExpiryDate = Math.ceil(new Date().getTime() / 1000) - 3600; // 1 hour ago + + const activityId = uuid(); + const propositionId = uuid(); + const itemId = uuid(); + + const responseBody = createMockResponse({ + scope: surface, + activityId, + propositionId, + items: [ + { + id: itemId, + schema: "https://ns.adobe.com/personalization/ruleset-item", + data: { + version: 1, + rules: [ + { + condition: { + definition: { + conditions: [ + { + definition: { + key: "~timestampu", + matcher: "le", + values: [mockExpiryDate], + }, + type: "matcher", + }, + ], + logic: "and", + }, + type: "group", + }, + consequences: [ + { + type: "schema", + detail: { + schema: + "https://ns.adobe.com/personalization/message/content-card", + data: { + expiryDate: mockExpiryDate, + publishedDate: mockPublishedDate, + meta: { + surface, + }, + content: { + shouldPinToTop: false, + imageUrl: + "https://raw.githubusercontent.com/jasonwaters/assets/master/2024/05/img_20240523_1716483354.png", + actionTitle: "Expired Action", + actionUrl: "https://paypal.com", + body: "This card should not be displayed", + title: "Expired Card", + }, + contentType: "application/json", + }, + id: itemId, + }, + id: itemId, + }, + ], + }, + ], + }, + }, + ], + }); + + await addHtmlToBody(testPageBody, true); + + const alloy = createAlloyProxy(); + await alloy.configure(config); + await alloy.applyResponse({ + renderDecisions: true, + responseBody, + }); + + let displayEventCalled = false; + + await alloy.subscribeRulesetItems({ + surfaces: [surface], + schemas: ["https://ns.adobe.com/personalization/message/content-card"], + callback: (result, collectEvent) => { + function createContentCard(proposition, item) { + const { data = {} } = item; + const { + content = {}, + meta = {}, + publishedDate, + qualifiedDate, + displayedDate, + } = data; + + return Object.assign({}, content, { + meta, + qualifiedDate, + displayedDate, + publishedDate, + getProposition: () => proposition, + }); + } + + function extractContentCards(propositions) { + return propositions + .reduce((allItems, proposition) => { + const { items = [] } = proposition; + return allItems.concat( + items.map((item) => createContentCard(proposition, item)), + ); + }, []) + .sort( + (a, b) => + b.qualifiedDate - a.qualifiedDate || + b.publishedDate - a.publishedDate, + ); + } + + const { propositions = [] } = result; + const contentCards = extractContentCards(propositions); + + const ul = document.getElementById("content-cards"); + let html = ""; + contentCards.forEach((contentCard, idx) => { + html += `
  • Item Image
    ${contentCard.title}

    ${contentCard.body}

  • `; + }); + ul.innerHTML = html; + + if (contentCards.length > 0) { + displayEventCalled = true; + collectEvent("display", propositions); + } + }, + }); + + await alloy.evaluateRulesets({ + renderDecisions: true, + personalization: { + decisionContext: {}, + }, + }); + + // Assert that no content cards are rendered + await t.expect(Selector("#content-cards").childElementCount).eql(0); + + // Verify that no display event was called + await t.expect(displayEventCalled).eql(false); + + // Verify that no network requests were made for display events + await t.expect(edgeEndpointLogs.count(() => true)).eql(0); +}); + +test("Test C1234567: Content card interaction tracking", async () => { + const surface = "web://mywebsite.com/#interaction-tracking"; + + const mockPublishedDate = Math.ceil(new Date().getTime() / 1000) - 864000; + const mockExpiryDate = Math.ceil(new Date().getTime() / 1000) + 864000; + + const activityId = uuid(); + const propositionId = uuid(); + const itemId = uuid(); + + const responseBody = createMockResponse({ + scope: surface, + activityId, + propositionId, + items: [ + { + id: itemId, + schema: "https://ns.adobe.com/personalization/ruleset-item", + data: { + version: 1, + rules: [ + { + condition: { + definition: { + conditions: [ + { + definition: { + key: "~timestampu", + matcher: "le", + values: [mockExpiryDate], + }, + type: "matcher", + }, + ], + logic: "and", + }, + type: "group", + }, + consequences: [ + { + type: "schema", + detail: { + schema: + "https://ns.adobe.com/personalization/message/content-card", + data: { + expiryDate: mockExpiryDate, + publishedDate: mockPublishedDate, + meta: { + surface, + }, + content: { + shouldPinToTop: false, + imageUrl: + "https://raw.githubusercontent.com/jasonwaters/assets/master/2024/05/img_20240523_1716483354.png", + actionTitle: "Expired Action", + actionUrl: "https://paypal.com", + body: "This card should not be displayed", + title: "Expired Card", + }, + contentType: "application/json", + }, + id: itemId, + }, + id: itemId, + }, + ], + }, + ], + }, + }, + ], + }); + + await addHtmlToBody(testPageBody, true); + + const alloy = createAlloyProxy(); + await alloy.configure(config); + await alloy.applyResponse({ + renderDecisions: true, + responseBody, + }); + + await alloy.subscribeRulesetItems({ + surfaces: [surface], + schemas: ["https://ns.adobe.com/personalization/message/content-card"], + callback: (result, collectEvent) => { + function createContentCard(proposition, item) { + const { data = {} } = item; + const { + content = {}, + meta = {}, + publishedDate, + qualifiedDate, + displayedDate, + } = data; + + return Object.assign({}, content, { + meta, + qualifiedDate, + displayedDate, + publishedDate, + getProposition: () => proposition, + }); + } + + function extractContentCards(propositions) { + return propositions + .reduce((allItems, proposition) => { + const { items = [] } = proposition; + return allItems.concat( + items.map((item) => createContentCard(proposition, item)), + ); + }, []) + .sort( + (a, b) => + b.qualifiedDate - a.qualifiedDate || + b.publishedDate - a.publishedDate, + ); + } + + const { propositions = [] } = result; + const contentCards = extractContentCards(propositions); + + const ul = document.getElementById("content-cards"); + let html = ""; + contentCards.forEach((contentCard, idx) => { + html += `
  • Item Image
    ${contentCard.title}

    ${contentCard.body}

    ${contentCard.actionTitle}
  • `; + }); + ul.innerHTML = html; + + collectEvent("display", propositions); + + ul.addEventListener("click", (evt) => { + const li = evt.target.closest("li"); + if (!li) { + return; + } + collectEvent("interact", [ + contentCards[li.dataset.idx].getProposition(), + ]); + }); + }, + }); + + await alloy.evaluateRulesets({ + renderDecisions: true, + personalization: { + decisionContext: {}, + }, + }); + + // Verify that the content card is rendered + await t.expect(Selector("#content-cards").childElementCount).eql(1); + + // Verify display event + const displayEvent = await getHistoricEventFromLocalStorage( + orgId, + activityId, + "display", + ); + + if (displayEvent !== null) { + await t.expect(displayEvent.count).eql(1); + } + + // Simulate user interaction (click on the action link) + await t.click("#content-card-0 .action-link"); + await t.wait(REASONABLE_WAIT_TIME); + + // Verify interact event + const interactEvent = await getHistoricEventFromLocalStorage( + orgId, + activityId, + "interact", + ); + + if (interactEvent !== null) { + await t.expect(interactEvent.count).eql(1); + } + + // Validate network requests + await responseStatus(edgeEndpointLogs.requests, [200, 204, 207]); + const requestCount = await edgeEndpointLogs.count(() => true); + + // Final assertions + await t + .expect(requestCount) + .gte(1, "At least one network request should be made"); + if (displayEvent !== null) { + await t + .expect(displayEvent.count) + .eql(1, "Display event should be recorded"); + } + if (interactEvent !== null) { + await t + .expect(interactEvent.count) + .eql(1, "Interact event should be recorded"); + } +}); diff --git a/packages/browser/test/functional/specs/Personalization/C14286730.js b/packages/browser/test/functional/specs/Personalization/C14286730.js new file mode 100644 index 000000000..4c13085c6 --- /dev/null +++ b/packages/browser/test/functional/specs/Personalization/C14286730.js @@ -0,0 +1,90 @@ +/* +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 } from "testcafe"; +import createNetworkLogger from "../../helpers/networkLogger/index.js"; +import { responseStatus } from "../../helpers/assertions/index.js"; +import createFixture from "../../helpers/createFixture/index.js"; +import { + compose, + orgMainConfigMain, + debugEnabled, + clickCollectionEventGroupingDisabled, +} from "../../helpers/constants/configParts/index.js"; +import { TEST_PAGE as TEST_PAGE_URL } from "../../helpers/constants/url.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; +import addHtmlToBody from "../../helpers/dom/addHtmlToBody.js"; + +const networkLogger = createNetworkLogger(); +const config = compose( + orgMainConfigMain, + debugEnabled, + clickCollectionEventGroupingDisabled, +); + +createFixture({ + title: "C14286730: Target SPA click interaction includes viewName", + requestHooks: [networkLogger.edgeEndpointLogs], + url: `${TEST_PAGE_URL}?test=C14286730`, +}); + +test.meta({ + ID: "C28755", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +test("Test C14286730: Target SPA click interaction includes viewName", async () => { + const alloy = createAlloyProxy(); + await alloy.configure(config); + + await addHtmlToBody( + `
    Products
    `, + ); + await alloy.sendEvent({ + renderDecisions: true, + xdm: { + web: { + webPageDetails: { + viewName: "products", + }, + }, + }, + }); + + await responseStatus(networkLogger.edgeEndpointLogs.requests, [200, 207]); + + // await t.expect(networkLogger.edgeEndpointLogs.count(() => true)).eql(2); + + await t.click(".clickme"); + + // await t.expect(networkLogger.edgeEndpointLogs.count(() => true)).eql(3); + + const displayNotification = JSON.parse( + networkLogger.edgeEndpointLogs.requests[1].request.body, + ); + + // TODO: Testcafe no longer captures the request body for sendBeacon requests. + // We could enhance this test to use Assurance to verify the request body. + // const interactNotification = JSON.parse( + // networkLogger.edgeEndpointLogs.requests[2].request.body, + // ); + // + await t + .expect(displayNotification.events[0].xdm.web.webPageDetails.viewName) + .eql("products"); + + // TODO: Testcafe no longer captures the request body for sendBeacon requests. + // We could enhance this test to use Assurance to verify the request body. + // await t + // .expect(interactNotification.events[0].xdm.web.webPageDetails.viewName) + // .eql("products"); +}); diff --git a/packages/browser/test/functional/specs/Personalization/C14299419.js b/packages/browser/test/functional/specs/Personalization/C14299419.js new file mode 100644 index 000000000..1260bef85 --- /dev/null +++ b/packages/browser/test/functional/specs/Personalization/C14299419.js @@ -0,0 +1,47 @@ +/* +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, Selector } from "testcafe"; +import createFixture from "../../helpers/createFixture/index.js"; +import { + compose, + orgMainConfigMain, + debugEnabled, +} from "../../helpers/constants/configParts/index.js"; +import { TEST_PAGE as TEST_PAGE_URL } from "../../helpers/constants/url.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; +import addHtmlToHeader from "../../helpers/dom/addHtmlToHeader.js"; + +const config = compose(orgMainConfigMain, debugEnabled); + +createFixture({ + title: + "C14299419: Prehiding style is removed when no personalization payload is returned", + url: `${TEST_PAGE_URL}?test=C14299419`, +}); + +test.meta({ + ID: "C14299419", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +test("Test C14299419: Prehiding style is removed when no personalization payload is returned", async () => { + await addHtmlToHeader( + ` - - - - -`; - -export const testPageBody = ` - -
    - - target offer -

    - This is a sample web page. It leverages the Adobe Experience Platform Web - SDK and APIs - to render personalization content. -

    -

    - Vestibulum cursus tristique risus, volutpat lobortis quam fermentum dapibus. Sed lacus augue, vulputate a placerat - vel, fringilla sed velit. In aliquet odio ut efficitur gravida. Vivamus volutpat hendrerit nisl ut rutrum. Donec - id nunc dolor. Pellentesque lectus mi, consequat sit amet elit vitae, laoreet euismod est. Cras placerat ex - ligula, nec malesuada dolor feugiat ut. Ut condimentum ante turpis, a iaculis massa cursus vitae. Sed sed felis - quam. Sed hendrerit, nisl vel viverra viverra, nisi mauris laoreet tortor, ut blandit lectus lacus ut tellus. - Integer ante sapien, tincidunt ut erat id, volutpat finibus urna. Aliquam rhoncus tellus vitae facilisis varius. -

    - -
    - - - -
    -
    -`; diff --git a/packages/core/test/functional/fixtures/Personalization/C9932846.js b/packages/core/test/functional/fixtures/Personalization/C9932846.js deleted file mode 100644 index 0a9946d4f..000000000 --- a/packages/core/test/functional/fixtures/Personalization/C9932846.js +++ /dev/null @@ -1,25 +0,0 @@ -/* -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. -*/ -export const testPageBody = ` -
    -
    - -
    -
    -

    AJO Personalization

    -
    -
    -
    - -`; diff --git a/packages/core/test/functional/fixtures/Personalization/conflictResolution.js b/packages/core/test/functional/fixtures/Personalization/conflictResolution.js deleted file mode 100644 index 88a493ca0..000000000 --- a/packages/core/test/functional/fixtures/Personalization/conflictResolution.js +++ /dev/null @@ -1,251 +0,0 @@ -/* -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. -*/ -export const inAppMessagesPropositions = { - requestId: "09ead9d7-b91f-41d6-9bb5-e7a5396315d6", - handle: [ - { - payload: [ - { - id: "03560676528201411421379778603411811904", - namespace: { - code: "ECID", - }, - }, - ], - type: "identity:result", - }, - { - payload: [ - { - id: "id2", - scope: "web://www.test.com/", - scopeDetails: { - rank: 2, - decisionProvider: "AJO", - correlationID: "3a034993-3bdb-4d8d-870f-0817e8949ebd-0", - characteristics: { - eventToken: - "eyJtZXNzYWdlRXhlY3V0aW9uIjp7Im1lc3NhZ2VFeGVjdXRpb25JRCI6IlVFOkluYm91bmQiLCJtZXNzYWdlSUQiOiIxYmQ4NWMwMC1iNGM5LTQ0NjQtYjIyMC1hYzY5ZTY5NGI1M2QiLCJtZXNzYWdlUHVibGljYXRpb25JRCI6IjNhMDM0OTkzLTNiZGItNGQ4ZC04NzBmLTA4MTdlODk0OWViZCIsIm1lc3NhZ2VUeXBlIjoibWFya2V0aW5nIiwiY2FtcGFpZ25JRCI6IjY4ODg5NDdjLTAyZDQtNDFhNi05YzZjLTE1YTU4ZTVlNzcyYyIsImNhbXBhaWduVmVyc2lvbklEIjoiNDU1NzE2MmQtNzgyMi00Zjg4LTkyZWItMmMxZmViZTFhMmViIiwiY2FtcGFpZ25BY3Rpb25JRCI6ImNhMzJlZjZmLWY3NTItNDA2Ny04YmFlLTE1NGY2MDAyN2E3ZSJ9LCJtZXNzYWdlUHJvZmlsZSI6eyJtZXNzYWdlUHJvZmlsZUlEIjoiYjBlM2M0YjctMWE3YS00NTljLWE2YzUtNTFlNDU0ZDVjYmRiIiwiY2hhbm5lbCI6eyJfaWQiOiJodHRwczovL25zLmFkb2JlLmNvbS94ZG0vY2hhbm5lbHMvaW5BcHAiLCJfdHlwZSI6Imh0dHBzOi8vbnMuYWRvYmUuY29tL3hkbS9jaGFubmVsLXR5cGVzL2luQXBwIn19fQ==", - }, - activity: { - id: "6888947c-02d4-41a6-9c6c-15a58e5e772c#ca32ef6f-f752-4067-8bae-154f60027a7e", - matchedSurfaces: ["web://surface1/"], - }, - }, - items: [ - { - id: "e1090531-caee-4749-a738-680f393cf4a9", - schema: "https://ns.adobe.com/personalization/ruleset-item", - data: { - version: 1, - rules: [ - { - condition: { - definition: { - key: "~type", - matcher: "eq", - values: ["com.adobe.eventType.rulesEngine"], - }, - type: "matcher", - }, - consequences: [ - { - id: "f03980c9-5344-4e32-84c7-d74ffebf06d6", - type: "schema", - detail: { - id: "f03980c9-5344-4e32-84c7-d74ffebf06d6", - schema: - "https://ns.adobe.com/personalization/message/in-app", - data: { - content: - "Proposition 2", - contentType: "text/html", - remoteAssets: [ - "https://cdn.experience.adobe.net/solutions/cjm-inapp-editor/assets/InAppBlockImageDefault.aa849e19.svg", - ], - webParameters: { - "alloy-content-iframe": { - style: { - border: "none", - height: "100%", - width: "100%", - }, - params: { - enabled: true, - insertionMethod: "appendChild", - parentElement: "#alloy-messaging-container", - }, - }, - "alloy-messaging-container": { - style: { - backgroundColor: "#000000", - border: "none", - borderRadius: "15px", - height: "100vh", - overflow: "hidden", - position: "fixed", - width: "100%", - left: "50%", - transform: - "translateX(-50%) translateY(-50%)", - top: "50%", - }, - params: { - enabled: true, - insertionMethod: "appendChild", - parentElement: "body", - }, - }, - "alloy-overlay-container": { - style: { - position: "fixed", - top: "0", - left: "0", - width: "100%", - height: "100%", - background: "transparent", - opacity: 0.2, - backgroundColor: "#000000", - }, - params: { - enabled: true, - insertionMethod: "appendChild", - parentElement: "body", - }, - }, - }, - publishedDate: 1727568749, - }, - }, - }, - ], - }, - ], - }, - }, - ], - }, - { - id: "id1", - scope: "web://www.test.com/", - scopeDetails: { - rank: 1, - decisionProvider: "AJO", - correlationID: "d4f5d677-1123-4605-ad9e-86fead923220-0", - characteristics: { - eventToken: - "eyJtZXNzYWdlRXhlY3V0aW9uIjp7Im1lc3NhZ2VFeGVjdXRpb25JRCI6IlVFOkluYm91bmQiLCJtZXNzYWdlSUQiOiJiNmY1ODVmZS1mNWE1LTQ0NWUtYjU0OC0yOThlMmQ1MDFkZTYiLCJtZXNzYWdlUHVibGljYXRpb25JRCI6ImQ0ZjVkNjc3LTExMjMtNDYwNS1hZDllLTg2ZmVhZDkyMzIyMCIsIm1lc3NhZ2VUeXBlIjoibWFya2V0aW5nIiwiY2FtcGFpZ25JRCI6ImI3NWNkNDAyLTIwNzMtNDc5OC1hMDJjLTc0YmQyMDg0MmQyNyIsImNhbXBhaWduVmVyc2lvbklEIjoiMmExMDJjZDMtZmM0NC00ZDI0LWEzMWMtNzZhZTBmY2FjMWJhIiwiY2FtcGFpZ25BY3Rpb25JRCI6ImNhMzJlZjZmLWY3NTItNDA2Ny04YmFlLTE1NGY2MDAyN2E3ZSJ9LCJtZXNzYWdlUHJvZmlsZSI6eyJtZXNzYWdlUHJvZmlsZUlEIjoiNzEyZjYwN2UtNjNmNS00NGExLTg3ZDYtM2Y1NWQzYjVmNGM2IiwiY2hhbm5lbCI6eyJfaWQiOiJodHRwczovL25zLmFkb2JlLmNvbS94ZG0vY2hhbm5lbHMvaW5BcHAiLCJfdHlwZSI6Imh0dHBzOi8vbnMuYWRvYmUuY29tL3hkbS9jaGFubmVsLXR5cGVzL2luQXBwIn19fQ==", - }, - activity: { - id: "b75cd402-2073-4798-a02c-74bd20842d27#ca32ef6f-f752-4067-8bae-154f60027a7e", - matchedSurfaces: ["web://surface1/"], - }, - }, - items: [ - { - id: "471af8f8-7806-47ce-885e-45fffe14108a", - schema: "https://ns.adobe.com/personalization/ruleset-item", - data: { - version: 1, - rules: [ - { - condition: { - definition: { - key: "~type", - matcher: "eq", - values: ["com.adobe.eventType.rulesEngine"], - }, - type: "matcher", - }, - consequences: [ - { - id: "613e9843-7291-4505-9cca-3f76caff6bec", - type: "schema", - detail: { - id: "613e9843-7291-4505-9cca-3f76caff6bec", - schema: - "https://ns.adobe.com/personalization/message/in-app", - data: { - content: - "Proposition 1", - contentType: "text/html", - remoteAssets: [ - "https://cdn.experience.adobe.net/solutions/cjm-inapp-editor/assets/InAppBlockImageDefault.aa849e19.svg", - ], - webParameters: { - "alloy-content-iframe": { - style: { - border: "none", - height: "100%", - width: "100%", - }, - params: { - enabled: true, - insertionMethod: "appendChild", - parentElement: "#alloy-messaging-container", - }, - }, - "alloy-messaging-container": { - style: { - backgroundColor: "#000000", - border: "none", - borderRadius: "15px", - height: "100vh", - overflow: "hidden", - position: "fixed", - width: "100%", - left: "50%", - transform: - "translateX(-50%) translateY(-50%)", - top: "50%", - }, - params: { - enabled: true, - insertionMethod: "appendChild", - parentElement: "body", - }, - }, - "alloy-overlay-container": { - style: { - position: "fixed", - top: "0", - left: "0", - width: "100%", - height: "100%", - background: "transparent", - opacity: 0.2, - backgroundColor: "#000000", - }, - params: { - enabled: true, - insertionMethod: "appendChild", - parentElement: "body", - }, - }, - }, - publishedDate: 1727568995, - }, - }, - }, - ], - }, - ], - }, - }, - ], - }, - ], - type: "personalization:decisions", - eventIndex: 0, - }, - ], -}; diff --git a/packages/core/test/functional/helpers/areThirdPartyCookiesSupported.js b/packages/core/test/functional/helpers/areThirdPartyCookiesSupported.js deleted file mode 100644 index ec79f779d..000000000 --- a/packages/core/test/functional/helpers/areThirdPartyCookiesSupported.js +++ /dev/null @@ -1,30 +0,0 @@ -/* -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 } from "testcafe"; -import { - CHROME, - CHROMIUM, - EDGE, - INTERNET_EXPLORER, -} from "./constants/browsers.js"; - -const browsersSupportingThirdPartyCookiesByDefault = [ - CHROME, - CHROMIUM, - EDGE, - INTERNET_EXPLORER, -]; - -// This must be a function called during the test, otherwise TestCafe will throw -// an error about how it can't resolve the right context for "t". -export default () => - browsersSupportingThirdPartyCookiesByDefault.indexOf(t.browser.name) !== -1; diff --git a/packages/core/test/functional/helpers/assertions/advertising.js b/packages/core/test/functional/helpers/assertions/advertising.js deleted file mode 100644 index cec1babae..000000000 --- a/packages/core/test/functional/helpers/assertions/advertising.js +++ /dev/null @@ -1,217 +0,0 @@ -/* -Copyright 2025 Adobe. All rights reserved. -This file is licensed to you under the Apache License, Version 2.0 (the "License"); -*/ -import { t } from "testcafe"; - -// Constants -export const ADVERTISING_CONSTANTS = Object.freeze({ - DEFAULT_ADVERTISER_SETTINGS: [ - { advertiserId: "83565", enabled: true }, - { advertiserId: "83567", enabled: true }, - { advertiserId: "83569", enabled: true }, - ], - DEFAULT_ADVERTISER_IDS_STRING: "83565, 83567, 83569", - DEFAULT_TIMEOUT: 15000, - EVENT_TYPES: { - CLICK_THROUGH: "advertising.enrichment_ct", - VIEW_THROUGH: "advertising.enrichment", - }, - ID5_PARTNER_ID: "173", - RAMP_ID_JS_PATH: "https://cdn.jsdelivr.net/npm/@liveramp/ats@2/ats.min.js", - EXPERIENCE_STRING: "_experience", - SAMPLE_SURFER_ID: "sample-surfer-id-12345", -}); - -// Helpers -const parseBody = (req) => { - try { - return JSON.parse(req?.request?.body) || {}; - } catch { - return {}; - } -}; - -const expectPath = async (obj, path, msg) => { - const val = path.split(".").reduce((o, k) => o?.[k], obj); - await t.expect(val).ok(msg); -}; - -// Config builder -export const createAdvertisingConfig = ({ - advertiserSettings = ADVERTISING_CONSTANTS.DEFAULT_ADVERTISER_SETTINGS, - id5PartnerId, - rampIdJSPath, - dspEnabled = true, -} = {}) => ({ - advertising: { - ...(advertiserSettings && { advertiserSettings }), - ...(id5PartnerId && { id5PartnerId }), - ...(rampIdJSPath && { rampIdJSPath }), - dspEnabled, - }, -}); - -// Finders -export const findClickThroughRequest = (requests) => - requests.find((req) => { - const body = parseBody(req); - const event = body.events?.[0]; - - const xdm = event?.xdm; - const eventType = xdm?.eventType; - - return eventType === ADVERTISING_CONSTANTS.EVENT_TYPES.CLICK_THROUGH; - }) || null; - -export const findViewThroughRequests = (requests) => - requests.filter((req) => { - const body = parseBody(req); - const event = body.events?.[0]; - - const hasAdvertisingQuery = !!event?.query?.advertising; - const hasViewThroughEventType = - event?.xdm?.eventType === ADVERTISING_CONSTANTS.EVENT_TYPES.VIEW_THROUGH; - - return hasAdvertisingQuery || hasViewThroughEventType; - }); - -export const findViewThroughRequestsWithXDM = (requests) => - requests.filter((req) => { - const body = parseBody(req); - const event = body.events?.[0]; - - return ( - event?.xdm?.eventType === ADVERTISING_CONSTANTS.EVENT_TYPES.VIEW_THROUGH - ); - }); - -// Validator for click-through -export const validateClickThroughRequest = async (req, expected) => { - const body = parseBody(req); - await expectPath(body, "events", "Missing events"); - - await t.expect(body.events.length).gte(1, "No events"); - - const adCloud = - body.events[0]?.xdm?.[ADVERTISING_CONSTANTS.EXPERIENCE_STRING]?.adcloud; - await t.expect(adCloud).ok("Missing adcloud"); - - const conversionDetails = adCloud.conversionDetails; - await t.expect(conversionDetails).ok("Missing conversionDetails"); - - // Validate eventType at the top level - const eventType = body.events[0]?.xdm?.eventType; - await t - .expect(eventType) - .eql("advertising.enrichment_ct", "eventType mismatch"); - - // Validate tracking code (skwcid) - if (expected.sampleGroupId !== undefined) { - await t - .expect(conversionDetails.trackingCode) - .eql(expected.sampleGroupId, "trackingCode mismatch"); - } - - // Validate tracking identities (efid) - if (expected.experimentId !== undefined) { - await t - .expect(conversionDetails.trackingIdentities) - .eql(expected.experimentId, "trackingIdentities mismatch"); - } -}; - -// Validator for view-through -export const validateViewThroughRequest = async (req, expected) => { - const body = parseBody(req); - await expectPath(body, "events", "Missing events"); - await t.expect(body.events.length).gte(1, "No events"); - - const event = body.events[0]; - - const eventType = event?.xdm?.eventType; - if (eventType) { - await t - .expect(eventType) - .eql( - ADVERTISING_CONSTANTS.EVENT_TYPES.VIEW_THROUGH, - "eventType should be advertising.enrichment for view-through", - ); - } - - const conv = event?.query?.advertising; - await t.expect(conv).ok("Missing advertising query"); - - await t.expect(conv.advIds).eql(expected.advIds, "advIds mismatch"); - - if (expected.requireIds !== false) { - const ids = conv.stitchIds || {}; - await t.expect(ids.surferId || ids.id5 || ids.rampIDEnv).ok("No IDs"); - } - - if (conv.lastDisplayClick) - await t.expect(typeof conv.lastDisplayClick).eql("string"); - if (conv.lastSearchClick) - await t.expect(typeof conv.lastSearchClick).eql("number"); -}; - -export const validateViewThroughRequestWithXDM = async (req, expected) => { - const body = parseBody(req); - await expectPath(body, "events", "Missing events"); - await t.expect(body.events.length).gte(1, "No events"); - - const event = body.events[0]; - - const eventType = event?.xdm?.eventType; - await t - .expect(eventType) - .eql( - ADVERTISING_CONSTANTS.EVENT_TYPES.VIEW_THROUGH, - "eventType should be advertising.enrichment for XDM view-through", - ); - - const conv = event?.query?.advertising; - await t.expect(conv).ok("Missing advertising query"); - - await t.expect(conv.advIds).eql(expected.advIds, "advIds mismatch"); - - if (expected.requireIds !== false) { - const ids = conv.stitchIds || {}; - await t.expect(ids.surferId || ids.id5 || ids.rampIDEnv).ok("No IDs"); - } - - if (conv.lastDisplayClick) - await t.expect(typeof conv.lastDisplayClick).eql("string"); - if (conv.lastSearchClick) - await t.expect(typeof conv.lastSearchClick).eql("number"); -}; - -// Best request selector -export const findBestRequestWithAdvertisingIds = (requests) => { - const viewReqs = findViewThroughRequests(requests); - if (viewReqs.length === 0) { - return null; - } - - let best = null; - let max = 0; - - viewReqs.forEach((r) => { - const stitch = - parseBody(r).events?.[0]?.query?.advertising?.stitchIds || {}; - const count = ["surferId", "id5", "rampIDEnv"].reduce( - (sum, key) => sum + (stitch[key] ? 1 : 0), - 0, - ); - if (count > max) { - max = count; - best = r; - } - }); - - // Always return at least the first request, with whatever maxIds we found - return { - bestRequest: best || viewReqs[0], - maxIds: max, - }; -}; diff --git a/packages/core/test/functional/helpers/assertions/index.js b/packages/core/test/functional/helpers/assertions/index.js deleted file mode 100644 index 5aa8d4d79..000000000 --- a/packages/core/test/functional/helpers/assertions/index.js +++ /dev/null @@ -1,13 +0,0 @@ -/* -Copyright 2025 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. -*/ -// Please keep in alphabetical order. -export { default as responseStatus } from "./responseStatus.js"; diff --git a/packages/core/test/functional/helpers/assertions/responseStatus.js b/packages/core/test/functional/helpers/assertions/responseStatus.js deleted file mode 100644 index b9ba7778f..000000000 --- a/packages/core/test/functional/helpers/assertions/responseStatus.js +++ /dev/null @@ -1,32 +0,0 @@ -/* -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 } from "testcafe"; - -const responseStatus = async (networkLogs, statuses) => { - if (!Array.isArray(statuses)) { - statuses = [statuses]; - } - - for (let i = 0; i < networkLogs.length; i += 1) { - const req = networkLogs[i]; - // TODO: Check why some requests don't have responses. - // TODO: It looks like test cafe might not be handling gzip correctly. - if (req.response) { - // eslint-disable-next-line no-await-in-loop - await t - .expect(statuses.includes(req.response.statusCode)) - .ok(`expected ${statuses} to be found in ${req.response.statusCode}`); - } - } -}; - -export default responseStatus; diff --git a/packages/core/test/functional/helpers/configureAlloyInstance/index.js b/packages/core/test/functional/helpers/configureAlloyInstance/index.js deleted file mode 100644 index c0b4d28db..000000000 --- a/packages/core/test/functional/helpers/configureAlloyInstance/index.js +++ /dev/null @@ -1,27 +0,0 @@ -/* -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 { ClientFunction } from "testcafe"; - -const configureAlloyInstance = ClientFunction((instanceName, cfg) => { - let finalInstanceName = instanceName; - let finalConfig = cfg; - - // Default instanceName to `alloy`. - if (typeof instanceName === "object" && instanceName !== null) { - finalInstanceName = "alloy"; - finalConfig = instanceName; - } - - return window[finalInstanceName]("configure", finalConfig); -}); - -export default configureAlloyInstance; diff --git a/packages/core/test/functional/helpers/consoleLogger/index.js b/packages/core/test/functional/helpers/consoleLogger/index.js deleted file mode 100644 index be36c503b..000000000 --- a/packages/core/test/functional/helpers/consoleLogger/index.js +++ /dev/null @@ -1,147 +0,0 @@ -/* -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 } from "testcafe"; - -const logLevels = ["log", "info", "warn", "error"]; - -const containsMessageMatchingRegex = (messages, messageRegex) => - messages.find((message) => messageRegex.test(message)) !== undefined; - -const formatFoundMessages = (messages) => { - if (!messages.length) { - return "No messages found."; - } - - return `Messages found:\n${messages.join("\n")}`; -}; - -/** - * Creates an object that can used for asserting the messages are or are not - * logged. The assertions will be made again all messages that occur after the - * logger has been created. - * - * For each log level (log, info, warn, error), there are assertion methods - * available. - * - * For example, here is how you would test that, at the "warn" - * log level, a message matching a given regex was logged: - * - * await logger.warn.expectMessageMatching(/test/); - * - * Here is how you would test that, at the "warn" log level, no messages - * matching a given regex was logged: - * - * await logger.warn.expectNoMessageMatching(/test/); - * - * Here is how you would test that, at the "warn log level, no messages - * were logged: - * - * await logger.warn.expectNoMessages(); - * - * There is also a method directly on the logger that resets all messages at - * all log levels: - * - * await logger.reset(); - */ -const createConsoleLogger = async () => { - let cursorByLogLevel; - const updateCursorByLogLevel = (messages) => { - cursorByLogLevel = logLevels.reduce((memo, logLevel) => { - memo[logLevel] = messages[logLevel].length; - return memo; - }, {}); - }; - - const messagesWhenCreated = await t.getBrowserConsoleMessages(); - updateCursorByLogLevel(messagesWhenCreated); - - // testCafe just calls toString on each parameter to the console log, so when - // logging objects, it just shows [object Object]. So this JSON stringifys the - // args and logs that. - await t.eval( - () => { - logLevels.forEach((logLevel) => { - const original = window.console[logLevel]; - window.console[logLevel] = (...args) => original(JSON.stringify(args)); - }); - }, - { dependencies: { logLevels } }, - ); - - const getMessagesSinceReset = async (logLevel) => { - const consoleMessages = await t.getBrowserConsoleMessages(); - const messagesForLevel = consoleMessages[logLevel]; - return messagesForLevel - .slice(cursorByLogLevel[logLevel]) - .map((message) => JSON.parse(message)); - }; - - const getMessagesSinceResetAsStrings = async (logLevel) => { - const messages = await getMessagesSinceReset(logLevel); - return messages.map((message) => - message.map((part) => part?.toString()).join(" "), - ); - }; - - const reset = async () => { - const messages = await t.getBrowserConsoleMessages(); - updateCursorByLogLevel(messages); - }; - - const expectMessageMatching = async (logLevel, messageRegex) => { - const messages = await getMessagesSinceResetAsStrings(logLevel); - await t - .expect(containsMessageMatchingRegex(messages, messageRegex)) - .ok( - `No message was found at "${logLevel}" log level matching ${messageRegex}. ${formatFoundMessages( - messages, - )}`, - ); - }; - - const expectNoMessageMatching = async (logLevel, messageRegex) => { - const messages = await getMessagesSinceResetAsStrings(logLevel); - await t - .expect(containsMessageMatchingRegex(messages, messageRegex)) - .notOk( - `A message was found at "${logLevel}" log level matching ${messageRegex} when none was expected.`, - ); - }; - - const expectNoMessages = async (logLevel) => { - const messages = await getMessagesSinceResetAsStrings(logLevel); - await t - .expect(messages.length) - .notOk( - `Messages were found "${logLevel}" at log level when none were expected. ${formatFoundMessages( - messages, - )}`, - ); - }; - - const methodsByLogLevel = logLevels.reduce((memo, logLevel) => { - memo[logLevel] = { - expectMessageMatching: expectMessageMatching.bind(null, logLevel), - expectNoMessageMatching: expectNoMessageMatching.bind(null, logLevel), - expectNoMessages: expectNoMessages.bind(null, logLevel), - getMessagesSinceReset: getMessagesSinceReset.bind(null, logLevel), - }; - return memo; - }, {}); - - return { - reset, - ...methodsByLogLevel, - }; -}; - -export default createConsoleLogger; diff --git a/packages/core/test/functional/helpers/constants/alloyEnvironment.js b/packages/core/test/functional/helpers/constants/alloyEnvironment.js deleted file mode 100644 index 2366725d0..000000000 --- a/packages/core/test/functional/helpers/constants/alloyEnvironment.js +++ /dev/null @@ -1,14 +0,0 @@ -/* -Copyright 2021 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. -*/ - -export const INTEGRATION = "int"; -export const PRODUCTION = "prod"; diff --git a/packages/core/test/functional/helpers/constants/browsers.js b/packages/core/test/functional/helpers/constants/browsers.js deleted file mode 100644 index d61d2f5d2..000000000 --- a/packages/core/test/functional/helpers/constants/browsers.js +++ /dev/null @@ -1,19 +0,0 @@ -/* -Copyright 2020 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. -*/ - -// The values here match those listed in -// https://github.com/lancedikson/bowser/blob/9ecf3e94c3269ef8bb4c8274dab6a31eea665aea/src/constants.js -// which is the library that provides the value for t.browser.name. -export const CHROME = "Chrome"; -export const CHROMIUM = "Chromium"; -export const EDGE = "Microsoft Edge"; -export const INTERNET_EXPLORER = "Internet Explorer"; diff --git a/packages/core/test/functional/helpers/constants/configParts/ajoConfigForStage.js b/packages/core/test/functional/helpers/constants/configParts/ajoConfigForStage.js deleted file mode 100644 index 6d79fcce5..000000000 --- a/packages/core/test/functional/helpers/constants/configParts/ajoConfigForStage.js +++ /dev/null @@ -1,17 +0,0 @@ -/* -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. -*/ -export default { - edgeDomain: "edge-int.adobedc.net", - datastreamId: "19fc5fe9-37df-46da-8f5c-9eeff4f75ed9", - orgId: "745F37C35E4B776E0A49421B@AdobeOrg", - edgeBasePath: "ee", -}; diff --git a/packages/core/test/functional/helpers/constants/configParts/clickCollectionDisabled.js b/packages/core/test/functional/helpers/constants/configParts/clickCollectionDisabled.js deleted file mode 100644 index 52e4cd9d8..000000000 --- a/packages/core/test/functional/helpers/constants/configParts/clickCollectionDisabled.js +++ /dev/null @@ -1,14 +0,0 @@ -/* -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. -*/ -export default { - clickCollectionEnabled: false, -}; diff --git a/packages/core/test/functional/helpers/constants/configParts/clickCollectionEnabled.js b/packages/core/test/functional/helpers/constants/configParts/clickCollectionEnabled.js deleted file mode 100644 index f1bbcfd94..000000000 --- a/packages/core/test/functional/helpers/constants/configParts/clickCollectionEnabled.js +++ /dev/null @@ -1,14 +0,0 @@ -/* -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. -*/ -export default { - clickCollectionEnabled: true, -}; diff --git a/packages/core/test/functional/helpers/constants/configParts/clickCollectionEventGroupingDisabled.js b/packages/core/test/functional/helpers/constants/configParts/clickCollectionEventGroupingDisabled.js deleted file mode 100644 index 977a75658..000000000 --- a/packages/core/test/functional/helpers/constants/configParts/clickCollectionEventGroupingDisabled.js +++ /dev/null @@ -1,16 +0,0 @@ -/* -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. -*/ -export default { - clickCollection: { - eventGroupingEnabled: false, - }, -}; diff --git a/packages/core/test/functional/helpers/constants/configParts/clickCollectionSessionStorageDisabled.js b/packages/core/test/functional/helpers/constants/configParts/clickCollectionSessionStorageDisabled.js deleted file mode 100644 index 67daa8943..000000000 --- a/packages/core/test/functional/helpers/constants/configParts/clickCollectionSessionStorageDisabled.js +++ /dev/null @@ -1,16 +0,0 @@ -/* -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. -*/ -export default { - clickCollection: { - sessionStorageEnabled: false, - }, -}; diff --git a/packages/core/test/functional/helpers/constants/configParts/configOverridesAlt.js b/packages/core/test/functional/helpers/constants/configParts/configOverridesAlt.js deleted file mode 100644 index 36646d777..000000000 --- a/packages/core/test/functional/helpers/constants/configParts/configOverridesAlt.js +++ /dev/null @@ -1,29 +0,0 @@ -/* -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. -*/ -export default { - com_adobe_experience_platform: { - datasets: { - event: { - datasetId: "6336ff95ba16ca1c07b4c0db", - }, - }, - }, - com_adobe_analytics: { - reportSuites: ["unifiedjsqeonlymobileweb"], - }, - com_adobe_identity: { - idSyncContainerId: 30794, - }, - com_adobe_target: { - propertyToken: "aba5431a-9f59-f816-7d73-8e40c8f4c4fd", - }, -}; diff --git a/packages/core/test/functional/helpers/constants/configParts/configOverridesMain.js b/packages/core/test/functional/helpers/constants/configParts/configOverridesMain.js deleted file mode 100644 index 6748412e2..000000000 --- a/packages/core/test/functional/helpers/constants/configParts/configOverridesMain.js +++ /dev/null @@ -1,29 +0,0 @@ -/* -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. -*/ -export default { - com_adobe_experience_platform: { - datasets: { - event: { - datasetId: "6335faf30f5a161c0b4b1444", - }, - }, - }, - com_adobe_analytics: { - reportSuites: ["unifiedjsqeonly2"], - }, - com_adobe_identity: { - idSyncContainerId: 30793, - }, - com_adobe_target: { - propertyToken: "a15d008c-5ec0-cabd-7fc7-ab54d56f01e8", - }, -}; diff --git a/packages/core/test/functional/helpers/constants/configParts/consentIn.js b/packages/core/test/functional/helpers/constants/configParts/consentIn.js deleted file mode 100644 index 25f3aa05b..000000000 --- a/packages/core/test/functional/helpers/constants/configParts/consentIn.js +++ /dev/null @@ -1,14 +0,0 @@ -/* -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. -*/ -export default { - defaultConsent: "in", -}; diff --git a/packages/core/test/functional/helpers/constants/configParts/consentPending.js b/packages/core/test/functional/helpers/constants/configParts/consentPending.js deleted file mode 100644 index 40fd39cbb..000000000 --- a/packages/core/test/functional/helpers/constants/configParts/consentPending.js +++ /dev/null @@ -1,14 +0,0 @@ -/* -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. -*/ -export default { - defaultConsent: "pending", -}; diff --git a/packages/core/test/functional/helpers/constants/configParts/debugDisabled.js b/packages/core/test/functional/helpers/constants/configParts/debugDisabled.js deleted file mode 100644 index 5e6d1f28e..000000000 --- a/packages/core/test/functional/helpers/constants/configParts/debugDisabled.js +++ /dev/null @@ -1,14 +0,0 @@ -/* -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. -*/ -export default { - debugEnabled: false, -}; diff --git a/packages/core/test/functional/helpers/constants/configParts/debugEnabled.js b/packages/core/test/functional/helpers/constants/configParts/debugEnabled.js deleted file mode 100644 index 707d5c1b4..000000000 --- a/packages/core/test/functional/helpers/constants/configParts/debugEnabled.js +++ /dev/null @@ -1,14 +0,0 @@ -/* -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. -*/ -export default { - debugEnabled: true, -}; diff --git a/packages/core/test/functional/helpers/constants/configParts/edgeDomainFirstParty.js b/packages/core/test/functional/helpers/constants/configParts/edgeDomainFirstParty.js deleted file mode 100644 index 13d865bd2..000000000 --- a/packages/core/test/functional/helpers/constants/configParts/edgeDomainFirstParty.js +++ /dev/null @@ -1,16 +0,0 @@ -/* -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 { FIRST_PARTY_DOMAIN } from "../domain.js"; - -export default { - edgeDomain: FIRST_PARTY_DOMAIN, -}; diff --git a/packages/core/test/functional/helpers/constants/configParts/edgeDomainThirdParty.js b/packages/core/test/functional/helpers/constants/configParts/edgeDomainThirdParty.js deleted file mode 100644 index 0b0f37be8..000000000 --- a/packages/core/test/functional/helpers/constants/configParts/edgeDomainThirdParty.js +++ /dev/null @@ -1,16 +0,0 @@ -/* -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 { THIRD_PARTY_DOMAIN } from "../domain.js"; - -export default { - edgeDomain: THIRD_PARTY_DOMAIN, -}; diff --git a/packages/core/test/functional/helpers/constants/configParts/index.js b/packages/core/test/functional/helpers/constants/configParts/index.js deleted file mode 100644 index 84b0b509a..000000000 --- a/packages/core/test/functional/helpers/constants/configParts/index.js +++ /dev/null @@ -1,57 +0,0 @@ -/* -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 configOverridesMain from "./configOverridesMain.js"; -import configOverridesAlt from "./configOverridesAlt.js"; -import orgMainConfigMain from "./orgMainConfigMain.js"; -import orgAltConfigAlt from "./orgAltConfigAlt.js"; -import debugEnabled from "./debugEnabled.js"; -import debugDisabled from "./debugDisabled.js"; -import edgeDomainFirstParty from "./edgeDomainFirstParty.js"; -import edgeDomainThirdParty from "./edgeDomainThirdParty.js"; -import clickCollectionEnabled from "./clickCollectionEnabled.js"; -import clickCollectionDisabled from "./clickCollectionDisabled.js"; -import clickCollectionSessionStorageDisabled from "./clickCollectionSessionStorageDisabled.js"; -import clickCollectionEventGroupingDisabled from "./clickCollectionEventGroupingDisabled.js"; -import migrationEnabled from "./migrationEnabled.js"; -import targetMigrationEnabled from "./targetMigrationEnabled.js"; -import migrationDisabled from "./migrationDisabled.js"; -import consentIn from "./consentIn.js"; -import consentPending from "./consentPending.js"; -import thirdPartyCookiesEnabled from "./thirdPartyCookiesEnabled.js"; -import thirdPartyCookiesDisabled from "./thirdPartyCookiesDisabled.js"; -import ajoConfigForStage from "./ajoConfigForStage.js"; - -const compose = (...objects) => Object.assign({}, ...objects); - -export { - compose, - configOverridesMain, - configOverridesAlt, - orgMainConfigMain, - orgAltConfigAlt, - debugEnabled, - debugDisabled, - edgeDomainFirstParty, - edgeDomainThirdParty, - clickCollectionEnabled, - clickCollectionDisabled, - clickCollectionSessionStorageDisabled, - clickCollectionEventGroupingDisabled, - migrationEnabled, - migrationDisabled, - consentIn, - consentPending, - thirdPartyCookiesEnabled, - thirdPartyCookiesDisabled, - targetMigrationEnabled, - ajoConfigForStage, -}; diff --git a/packages/core/test/functional/helpers/constants/configParts/migrationDisabled.js b/packages/core/test/functional/helpers/constants/configParts/migrationDisabled.js deleted file mode 100644 index 13c60db23..000000000 --- a/packages/core/test/functional/helpers/constants/configParts/migrationDisabled.js +++ /dev/null @@ -1,14 +0,0 @@ -/* -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. -*/ -export default { - idMigrationEnabled: false, -}; diff --git a/packages/core/test/functional/helpers/constants/configParts/migrationEnabled.js b/packages/core/test/functional/helpers/constants/configParts/migrationEnabled.js deleted file mode 100644 index 9fde41f17..000000000 --- a/packages/core/test/functional/helpers/constants/configParts/migrationEnabled.js +++ /dev/null @@ -1,14 +0,0 @@ -/* -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. -*/ -export default { - idMigrationEnabled: true, -}; diff --git a/packages/core/test/functional/helpers/constants/configParts/orgAltConfigAlt.js b/packages/core/test/functional/helpers/constants/configParts/orgAltConfigAlt.js deleted file mode 100644 index d54c4e783..000000000 --- a/packages/core/test/functional/helpers/constants/configParts/orgAltConfigAlt.js +++ /dev/null @@ -1,16 +0,0 @@ -/* -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. -*/ -// TODO: Use a real config ID since 9999999 is going away. -// TODO: Need configs in `int` & prod`. -import getBaseConfig from "../../getBaseConfig.js"; - -export default getBaseConfig("53A16ACB5CC1D3760A495C99@AdobeOrg", "9999999"); diff --git a/packages/core/test/functional/helpers/constants/configParts/orgMainConfigMain.js b/packages/core/test/functional/helpers/constants/configParts/orgMainConfigMain.js deleted file mode 100644 index f9af8b099..000000000 --- a/packages/core/test/functional/helpers/constants/configParts/orgMainConfigMain.js +++ /dev/null @@ -1,14 +0,0 @@ -/* -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 getBaseConfig from "../../getBaseConfig.js"; - -export default getBaseConfig(); diff --git a/packages/core/test/functional/helpers/constants/configParts/orgMediaConfig.js b/packages/core/test/functional/helpers/constants/configParts/orgMediaConfig.js deleted file mode 100644 index 23acf6272..000000000 --- a/packages/core/test/functional/helpers/constants/configParts/orgMediaConfig.js +++ /dev/null @@ -1,17 +0,0 @@ -/* -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 getBaseConfig from "../../getBaseConfig.js"; - -export default getBaseConfig( - "97D1F3F459CE0AD80A495CBE@AdobeOrg", - "27dae196-8c75-4eed-82d1-3895616f85d6", -); diff --git a/packages/core/test/functional/helpers/constants/configParts/streamingMedia.js b/packages/core/test/functional/helpers/constants/configParts/streamingMedia.js deleted file mode 100644 index aa30aca69..000000000 --- a/packages/core/test/functional/helpers/constants/configParts/streamingMedia.js +++ /dev/null @@ -1,17 +0,0 @@ -/* -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. -*/ -export default { - streamingMedia: { - channel: "functional tests channel", - playerName: "functional test player", - }, -}; diff --git a/packages/core/test/functional/helpers/constants/configParts/targetMigrationEnabled.js b/packages/core/test/functional/helpers/constants/configParts/targetMigrationEnabled.js deleted file mode 100644 index 7e119414e..000000000 --- a/packages/core/test/functional/helpers/constants/configParts/targetMigrationEnabled.js +++ /dev/null @@ -1,14 +0,0 @@ -/* -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. -*/ -export default { - targetMigrationEnabled: true, -}; diff --git a/packages/core/test/functional/helpers/constants/configParts/thirdPartyCookiesDisabled.js b/packages/core/test/functional/helpers/constants/configParts/thirdPartyCookiesDisabled.js deleted file mode 100644 index 152107765..000000000 --- a/packages/core/test/functional/helpers/constants/configParts/thirdPartyCookiesDisabled.js +++ /dev/null @@ -1,15 +0,0 @@ -/* -Copyright 2020 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. -*/ - -export default { - thirdPartyCookiesEnabled: false, -}; diff --git a/packages/core/test/functional/helpers/constants/configParts/thirdPartyCookiesEnabled.js b/packages/core/test/functional/helpers/constants/configParts/thirdPartyCookiesEnabled.js deleted file mode 100644 index bda552f00..000000000 --- a/packages/core/test/functional/helpers/constants/configParts/thirdPartyCookiesEnabled.js +++ /dev/null @@ -1,15 +0,0 @@ -/* -Copyright 2020 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. -*/ - -export default { - thirdPartyCookiesEnabled: true, -}; diff --git a/packages/core/test/functional/helpers/constants/consent.js b/packages/core/test/functional/helpers/constants/consent.js deleted file mode 100644 index d1a476329..000000000 --- a/packages/core/test/functional/helpers/constants/consent.js +++ /dev/null @@ -1,145 +0,0 @@ -/* -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. -*/ -export const CONSENT_IN = { - consent: [ - { - standard: "Adobe", - version: "1.0", - value: { - general: "in", - }, - }, - ], -}; -export const CONSENT_OUT = { - consent: [ - { - standard: "Adobe", - version: "1.0", - value: { - general: "out", - }, - }, - ], -}; - -export const IAB_CONSENT_IN = { - consent: [ - { - standard: "IAB TCF", - version: "2.0", - value: "CO052l-O052l-DGAMBFRACBgAIBAAAAAAIYgEawAQEagAAAA", - gdprApplies: true, - }, - ], -}; - -export const IAB_CONSENT_IN_PERSONAL_DATA = { - consent: [ - { - standard: "IAB TCF", - version: "2.0", - value: "CO052l-O052l-DGAMBFRACBgAIBAAAAAAIYgEawAQEagAAAA", - gdprApplies: true, - gdprContainsPersonalData: true, - }, - ], -}; - -export const IAB_CONSENT_IN_NO_GDPR = { - consent: [ - { - standard: "IAB TCF", - version: "2.0", - value: "CO052l-O052l-DGAMBFRACBgAIBAAAAAAIYgEawAQEagAAAA", - gdprApplies: false, - }, - ], -}; - -export const IAB_NO_PURPOSE_ONE = { - consent: [ - { - standard: "IAB TCF", - version: "2.0", - value: "CO052oTO052oTDGAMBFRACBgAABAAAAAAIYgEawAQEagAAAA", - gdprApplies: true, - }, - ], -}; - -export const IAB_NO_PURPOSE_ONE_NO_GRPR = { - consent: [ - { - standard: "IAB TCF", - version: "2.0", - value: "CO052oTO052oTDGAMBFRACBgAABAAAAAAIYgEawAQEagAAAA", - gdprApplies: false, - }, - ], -}; - -export const IAB_NO_PURPOSE_TEN = { - consent: [ - { - standard: "IAB TCF", - version: "2.0", - value: "CO052kIO052kIDGAMBFRACBgAIAAAAAAAIYgEawAQEagAAAA", - gdprApplies: true, - }, - ], -}; - -export const IAB_NO_ADOBE_VENDOR = { - consent: [ - { - standard: "IAB TCF", - version: "2.0", - value: "CO052qdO052qdDGAMBFRACBgAIBAAAAAAIYgAAoAAAAA", - gdprApplies: true, - }, - ], -}; - -export const ADOBE2_IN = { - consent: [ - { - standard: "Adobe", - version: "2.0", - value: { - collect: { - val: "y", - }, - metadata: { - time: "2019-01-01T15:52:25+00:00", - }, - }, - }, - ], -}; - -export const ADOBE2_OUT = { - consent: [ - { - standard: "Adobe", - version: "2.0", - value: { - collect: { - val: "n", - }, - metadata: { - time: "2019-01-01T15:52:25+00:00", - }, - }, - }, - ], -}; diff --git a/packages/core/test/functional/helpers/constants/cookies.js b/packages/core/test/functional/helpers/constants/cookies.js deleted file mode 100644 index a6274e704..000000000 --- a/packages/core/test/functional/helpers/constants/cookies.js +++ /dev/null @@ -1,21 +0,0 @@ -/* -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. -*/ -export const MAIN_IDENTITY_COOKIE_NAME = - "kndctr_5BFE274A5F6980A50A495C08_AdobeOrg_identity"; -export const MAIN_CONSENT_COOKIE_NAME = - "kndctr_5BFE274A5F6980A50A495C08_AdobeOrg_consent"; -export const MAIN_CLUSTER_COOKIE_NAME = - "kndctr_5BFE274A5F6980A50A495C08_AdobeOrg_cluster"; -export const LEGACY_IDENTITY_COOKIE_NAME = - "AMCV_5BFE274A5F6980A50A495C08%40AdobeOrg"; -export const LEGACY_IDENTITY_COOKIE_UNESCAPED_NAME = - LEGACY_IDENTITY_COOKIE_NAME.replace("%40", "@"); diff --git a/packages/core/test/functional/helpers/constants/datastreamId.js b/packages/core/test/functional/helpers/constants/datastreamId.js deleted file mode 100644 index 669286658..000000000 --- a/packages/core/test/functional/helpers/constants/datastreamId.js +++ /dev/null @@ -1,12 +0,0 @@ -/* -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. -*/ -export default "bc1a10e0-aee4-4e0e-ac5b-cdbb9abbec83"; diff --git a/packages/core/test/functional/helpers/constants/deviceContextConfig.js b/packages/core/test/functional/helpers/constants/deviceContextConfig.js deleted file mode 100644 index 443318f16..000000000 --- a/packages/core/test/functional/helpers/constants/deviceContextConfig.js +++ /dev/null @@ -1,17 +0,0 @@ -/* -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 orgMainConfigMain from "./configParts/orgMainConfigMain.js"; - -export default { - context: ["device"], - ...orgMainConfigMain, -}; diff --git a/packages/core/test/functional/helpers/constants/domain.js b/packages/core/test/functional/helpers/constants/domain.js deleted file mode 100644 index 10d6ad15f..000000000 --- a/packages/core/test/functional/helpers/constants/domain.js +++ /dev/null @@ -1,14 +0,0 @@ -/* -Copyright 2020 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. -*/ - -export const THIRD_PARTY_DOMAIN = "edge.adobedc.net"; -export const FIRST_PARTY_DOMAIN = "firstparty.alloyio.com"; diff --git a/packages/core/test/functional/helpers/constants/environmentContextConfig.js b/packages/core/test/functional/helpers/constants/environmentContextConfig.js deleted file mode 100644 index ff3d845eb..000000000 --- a/packages/core/test/functional/helpers/constants/environmentContextConfig.js +++ /dev/null @@ -1,17 +0,0 @@ -/* -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 orgMainConfigMain from "./configParts/orgMainConfigMain.js"; - -export default { - context: ["environment"], - ...orgMainConfigMain, -}; diff --git a/packages/core/test/functional/helpers/constants/highEntropyUserAgentHintsContextConfig.js b/packages/core/test/functional/helpers/constants/highEntropyUserAgentHintsContextConfig.js deleted file mode 100644 index 562e5ccec..000000000 --- a/packages/core/test/functional/helpers/constants/highEntropyUserAgentHintsContextConfig.js +++ /dev/null @@ -1,17 +0,0 @@ -/* -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 orgMainConfigMain from "./configParts/orgMainConfigMain.js"; - -export default { - context: ["highEntropyUserAgentHints"], - ...orgMainConfigMain, -}; diff --git a/packages/core/test/functional/helpers/constants/placeContextConfig.js b/packages/core/test/functional/helpers/constants/placeContextConfig.js deleted file mode 100644 index a444a84c9..000000000 --- a/packages/core/test/functional/helpers/constants/placeContextConfig.js +++ /dev/null @@ -1,17 +0,0 @@ -/* -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 orgMainConfigMain from "./configParts/orgMainConfigMain.js"; - -export default { - context: ["placeContext"], - ...orgMainConfigMain, -}; diff --git a/packages/core/test/functional/helpers/constants/regex.js b/packages/core/test/functional/helpers/constants/regex.js deleted file mode 100644 index 822c1596f..000000000 --- a/packages/core/test/functional/helpers/constants/regex.js +++ /dev/null @@ -1,13 +0,0 @@ -/* -Copyright 2021 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. -*/ - -export const ECID = /^[0-9]{38}$/; diff --git a/packages/core/test/functional/helpers/constants/remoteVisitorLibraryUrl.js b/packages/core/test/functional/helpers/constants/remoteVisitorLibraryUrl.js deleted file mode 100644 index 10870ed3c..000000000 --- a/packages/core/test/functional/helpers/constants/remoteVisitorLibraryUrl.js +++ /dev/null @@ -1,13 +0,0 @@ -/* -Copyright 2020 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. -*/ - -export default "https://github.com/Adobe-Marketing-Cloud/id-service/releases/latest/download/visitorapi.min.js"; diff --git a/packages/core/test/functional/helpers/constants/url.js b/packages/core/test/functional/helpers/constants/url.js deleted file mode 100644 index 81f53b649..000000000 --- a/packages/core/test/functional/helpers/constants/url.js +++ /dev/null @@ -1,24 +0,0 @@ -/* -Copyright 2021 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. -*/ - -const baseUrl = `https://alloyio.com/functional-test`; - -export const TEST_PAGE = `${baseUrl}/testPage.html`; -export const TEST_PAGE_AT_JS_TWO = `${baseUrl}/testPageWithAtjs2.html`; -export const TEST_PAGE_AT_JS_ONE = `${baseUrl}/testPageWithAtjs1.html`; -export const TEST_PAGE_WITH_CSP = `${baseUrl}/testPageWithCsp.html`; -// This page is only used by reloadPage.js as an interim workaround for -// https://github.com/DevExpress/testcafe/issues/5992 -export const RELOAD_PAGE = `${baseUrl}/reloadPage.html`; - -const secondaryBaseUrl = `https://alloyio2.com/functional-test`; -export const SECONDARY_TEST_PAGE = `${secondaryBaseUrl}/testPage.html`; diff --git a/packages/core/test/functional/helpers/constants/webContextConfig.js b/packages/core/test/functional/helpers/constants/webContextConfig.js deleted file mode 100644 index 61bd1d3e4..000000000 --- a/packages/core/test/functional/helpers/constants/webContextConfig.js +++ /dev/null @@ -1,17 +0,0 @@ -/* -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 orgMainConfigMain from "./configParts/orgMainConfigMain.js"; - -export default { - context: ["web"], - ...orgMainConfigMain, -}; diff --git a/packages/core/test/functional/helpers/cookies.js b/packages/core/test/functional/helpers/cookies.js deleted file mode 100644 index aeabd22c8..000000000 --- a/packages/core/test/functional/helpers/cookies.js +++ /dev/null @@ -1,57 +0,0 @@ -/* -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 { ClientFunction, t } from "testcafe"; - -const blankOutCookieInBrowser = ClientFunction((name) => { - document.cookie = `${name}=;expires=Thu, 01 Jan 1970 00:00:00 GMT`; -}); - -export default { - clear: ClientFunction(() => { - const cookies = document.cookie.split(";"); - - for (let i = 0; i < cookies.length; i += 1) { - const cookie = cookies[i]; - const eqPos = cookie.indexOf("="); - const name = eqPos > -1 ? cookie.substr(0, eqPos) : cookie; - document.cookie = `${name}=;expires=Thu, 01 Jan 1970 00:00:00 GMT`; - } - }), - get: ClientFunction((name) => { - const cookies = document.cookie - .split(";") - .map((c) => { - const ct = c.trim(); - const index = ct.indexOf("="); - return [ct.slice(0, index), ct.slice(index + 1)].map( - decodeURIComponent, - ); - }) - .reduce((a, b) => { - try { - a[b[0]] = JSON.parse(b[1]); - } catch { - a[b[0]] = b[1]; - } - return a; - }, {}); - - return cookies[name] || undefined; - }), - async remove(name) { - // From testing, I noticed that Web SDK no longer has access to the cookies - // when we use cookies.remove, and the browser no longer has access to the cookies - // when we use t.deleteCookies. So I call both here. - await blankOutCookieInBrowser(name); - await t.deleteCookies(name); - }, -}; diff --git a/packages/core/test/functional/helpers/createAdobeMC.js b/packages/core/test/functional/helpers/createAdobeMC.js deleted file mode 100644 index e5e5d0375..000000000 --- a/packages/core/test/functional/helpers/createAdobeMC.js +++ /dev/null @@ -1,22 +0,0 @@ -/* -Copyright 2022 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 createRandomEcid from "./createRandomEcid.js"; -import { orgMainConfigMain } from "./constants/configParts/index.js"; - -export default ({ timestamp, id, orgId } = {}) => { - const ts = timestamp || new Date().getTime() / 1000; - const mcmid = id || createRandomEcid(); - const mcorgid = orgId || orgMainConfigMain.orgId; - - return encodeURIComponent(`TS=${ts}|MCMID=${mcmid}|MCORGID=${mcorgid}`); -}; diff --git a/packages/core/test/functional/helpers/createAlloyProxy.js b/packages/core/test/functional/helpers/createAlloyProxy.js deleted file mode 100644 index 3994ae235..000000000 --- a/packages/core/test/functional/helpers/createAlloyProxy.js +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Using TestCafe, the test code is run inside Node. If you want to run code inside the browser - * you have to use ClientFunctions or t.eval. TestCafe compiles and copies the code inside the - * ClientFunction or eval onto the browser page and then runs it. TestCafe also has a system for - * taking the return value and bringing (marshalling) it into Node. - * - * There are a few gotchas when using ClientFunction and t.eval with promises. First, promises are - * only marshalled when they are the only thing returned from the client function. If a promise is - * included as part of a returned object, the promise isn't marshalled correctly. Secondly, if you - * do not `await` the ClientFunction execution in the test, client functions may be executed out - * of order. Lastly, if an error is thrown on the browser inside the returned promise, the error is - * wrapped in a TestCafe error object. It is easier to get the error information if you catch the - * error inside the browser. Using this Alloy proxy avoids these pitfalls. - * - * To create a proxy, call the default export of this file like this: - * - * const alloy = createAlloyProxy(); - * - * You can pass in the name of the Alloy global variable if needed (it defaults to "alloy".) - * - * const instance2 = createAlloyProxy("instance2"); - * - * All the Alloy commands are implemented as methods on the returned proxy object. They return a - * marshalled promise from the Alloy command. Be sure to always use "await" when calling any method - * on the proxy. - * - * await alloy.configure(config); - * await alloy.sendEvent({ renderDecisions: true }); - * - * Additionally each command has a xxxErrorMessage variant that returns a promise that will resolve - * with undefined if there was no error, and the error message if there was an error. - * - * const errorMessage = await alloy.sendEventErrorMessage(); - * await t.expect(errorMessage).ok("Expected an error, but didn't get one"); - * await t.expect(errorMessage).contains("myerror"); - * - * Sometimes in a test you need to run other commands before a command finishes. For example, sending an - * event may not resolve until after consent is given. For these cases, each command has a xxxAsync variant - * that returns an object with two promises: "result", and "errorMessage". Both of these promises resolve - * when the command is finished. "result" will resolve to the result of the command, and errorMessage will - * resolve with undefined if there was no error, and the error message if there was an error. - * - * const sendEventResponse = await alloy.sendEventAsync(); - * await alloy.setConsent(...); - * await sendEventResponse.result; - * - */ -import { ClientFunction } from "testcafe"; - -const proxyFunction = ClientFunction((instanceName, command, options) => { - // return the promise from the client function - return window[instanceName](command, options); -}); - -const asyncProxyFunction = ClientFunction((instanceName, command, options) => { - // save the promise to a browser global variable to be referenced later - window.lastAlloyProxyPromise = window[instanceName](command, options); -}); - -const errorMessageProxyFunction = ClientFunction( - (instanceName, command, options) => { - // return a promise that resolves to the error message or undefined - return window[instanceName](command, options).then( - () => undefined, - (e) => e.message, - ); - }, -); - -const getLastPromise = ClientFunction(() => { - // fetch the last promise set by asyncProxyFunction - return window.lastAlloyProxyPromise; -}); - -const getLastErrorMessage = ClientFunction(() => { - // return a promise that resolves to the error message or undefined - // using the last promise set by asyncProxyFunction - return window.lastAlloyProxyPromise.then( - () => undefined, - (e) => e.message, - ); -}); - -const commands = [ - "configure", - "sendEvent", - "applyResponse", - "setConsent", - "getIdentity", - "setDebug", - "getLibraryInfo", - "appendIdentityToUrl", - "applyPropositions", - "subscribeRulesetItems", - "evaluateRulesets", - "createMediaSession", - "sendMediaEvent", - "getMediaAnalyticsTracker", -]; - -export default (instanceName = "alloy") => { - const proxy = {}; - commands.forEach((command) => { - // Run the command and return the result. - proxy[command] = (options) => proxyFunction(instanceName, command, options); - - // Run the command and return the error message or undefined. - proxy[`${command}ErrorMessage`] = (options) => - errorMessageProxyFunction(instanceName, command, options); - - // Run the command, but don't wait on the result. - proxy[`${command}Async`] = async (options) => { - // This command calls three separate ClientFunctions to get three promises: - // 1. We await on the TestCafe generated promise from running the client function. - // This ensures that commands are run in order - // 2. We get the promise from the command that will resolve to the result. - // 3. We get the error message from the command if there is one. - await asyncProxyFunction(instanceName, command, options); - return { result: getLastPromise(), errorMessage: getLastErrorMessage() }; - }; - }); - - return proxy; -}; diff --git a/packages/core/test/functional/helpers/createCollectEndpointAsserter.js b/packages/core/test/functional/helpers/createCollectEndpointAsserter.js deleted file mode 100644 index 4b8b5abb4..000000000 --- a/packages/core/test/functional/helpers/createCollectEndpointAsserter.js +++ /dev/null @@ -1,120 +0,0 @@ -/* -Copyright 2021 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 } from "testcafe"; -import createNetworkLogger from "./networkLogger/index.js"; -import sendBeaconMock from "./sendBeaconMock.js"; - -/** - * A useful utility when dealing with assertions related to - * the collect endpoint. Alloy sends requests to the collect endpoint - * using sendBeacon if sendBeacon is supported by the browser. When - * sendBeacon is called, the browser doesn't send the request right - * away, but instead queues the request to be sent sometime - * later, which can make it tricky to correctly assert that requests - * have or have not been sent to the endpoint. - */ -export default async () => { - const networkLogger = createNetworkLogger(); - await t.addRequestHooks( - networkLogger.edgeInteractEndpointLogs, - networkLogger.edgeCollectEndpointLogs, - ); - - await sendBeaconMock.mock(); - const assertCollectCalled = async () => { - // When sendBeacon is called, the browser doesn't send the request right away, - // but instead queues the request to be sent sometime later. Therefore, the - // sendEvent promise resolves before any network request may have actually been made. - // By calling the RequestLogger's count method, TestCafe will retry this - // assertion until it succeeds or until the timeout is reached. The parameter - // to count is a filter function. In this case, we want to count all the requests. - await t - .expect(networkLogger.edgeCollectEndpointLogs.count(() => true)) - .eql(1, "No network request to the collect endpoint was detected."); - // If sendBeacon is supported by the browser, we should always be using it when - // sending requests to the collect endpoint. - await t - .expect(sendBeaconMock.getCallCount()) - .eql(1, "No sendBeacon call was detected."); - }; - - const assertCollectNotCalled = async () => { - // When sendBeacon is called, the browser doesn't send the request right away, - // but instead queues the request to be sent sometime later. Therefore, the - // sendEvent promise resolves before any network request may have actually been made. - // In order to check that a request to the collect endpoint is never made, we would - // have to wait for an arbitrary period of time before checking that the number of - // network requests to the collect endpoint is 0. Instead of waiting for an arbitrary - // period of time, which is a fragile and slow solution, we'll make our best attempt - // at this assertion by checking that sendBeacon was never called. If supported by the - // browser, sendBeacon is solely used to send requests to collect, so it's a fair approximation. - await t - .expect(sendBeaconMock.getCallCount()) - .eql(0, "A network request to the collect endpoint was detected."); - }; - - const assertInteractCalled = async () => { - await t - .expect(networkLogger.edgeInteractEndpointLogs.requests.length) - .eql(1, "No network request to the interact endpoint was detected."); - }; - - const assertInteractNotCalled = async () => { - await t - .expect(networkLogger.edgeInteractEndpointLogs.requests.length) - .eql(0, "A network request to the interact endpoint was detected."); - }; - - let collectRequestAsserted = false; - let interactRequestAsserted = false; - return { - async assertCollectCalledAndNotInteract() { - collectRequestAsserted = true; - // The order of these matter because we need to make sure sendBeacon - // requests have actually been sent by the browser before checking - // that they weren't interact calls. - await assertCollectCalled(); - await assertInteractNotCalled(); - }, - async assertInteractCalledAndNotCollect() { - interactRequestAsserted = true; - await assertCollectNotCalled(); - await assertInteractCalled(); - }, - async assertNeitherCollectNorInteractCalled() { - await assertCollectNotCalled(); - await assertInteractNotCalled(); - }, - async reset() { - interactRequestAsserted = false; - collectRequestAsserted = false; - await networkLogger.clearLogs(); - await sendBeaconMock.reset(); - }, - getInteractRequest() { - if (!interactRequestAsserted) { - throw new Error( - "You must call assertInteractCalledAndNotCollect before getting the interact request", - ); - } - return networkLogger.edgeInteractEndpointLogs.requests[0]; - }, - getCollectRequest() { - if (!collectRequestAsserted) { - throw new Error( - "You must call assertCollectCalledAndNotInteract before getting the collect request", - ); - } - return networkLogger.edgeCollectEndpointLogs.requests[0]; - }, - }; -}; diff --git a/packages/core/test/functional/helpers/createFixture/clientScripts.js b/packages/core/test/functional/helpers/createFixture/clientScripts.js deleted file mode 100644 index b555daae4..000000000 --- a/packages/core/test/functional/helpers/createFixture/clientScripts.js +++ /dev/null @@ -1,223 +0,0 @@ -/* -Copyright 2020 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 path from "path"; -import fs from "fs"; -import readCache from "read-cache"; -import { ClientFunction } from "testcafe"; -import { INTEGRATION, PRODUCTION } from "../constants/alloyEnvironment.js"; -import REMOTE_VISITOR_LIBRARY_URL from "../constants/remoteVisitorLibraryUrl.js"; - -const alloyEnv = process.env.ALLOY_ENV || INTEGRATION; -const alloyProdVersion = process.env.ALLOY_PROD_VERSION; -// eslint-disable-next-line no-console -console.log(`ALLOY ENV: ${alloyEnv}`); - -if (alloyEnv === PRODUCTION) { - if (alloyProdVersion) { - // eslint-disable-next-line no-console - console.log(`ALLOY PROD VERSION: ${alloyProdVersion}`); - } else { - throw new Error( - "The ALLOY_PROD_VERSION environment variable must be provided when running against the production environment.", - ); - } -} -const rootDir = path.join(__dirname, "../../../../../../"); -const baseCodePath = path.join(rootDir, "distTest/baseCode.min.js"); -const localAlloyLibraryPath = path.join(rootDir, "dist/alloy.js"); -const localNpmLibraryPath = path.join(rootDir, "distTest/npmPackageLocal.js"); -const prodNpmLibraryPath = path.join(rootDir, "distTest/npmPackageProd.js"); -const remoteAlloyLibraryUrl = `https://cdn1.adoberesources.net/alloy/${alloyProdVersion}/alloy.js`; - -// We use this getter for retrieving the library code instead of just loading -// the library code a single time up-front, because we want every run to be -// using the latest library code. This is important when developing in watch -// mode and making changes to source files. -const getLocalAlloyCode = () => - // readCache caches file content until the file is modified, at which - // point it will retrieve fresh file content, cache it, and return it. - readCache.sync(localAlloyLibraryPath, "utf8"); -// This is the javascript built from src/index.js which does not include the -// baseCode, but exposes a createInstance function. -const getLocalNpmLibraryCode = () => - readCache.sync(localNpmLibraryPath, "utf8"); -// This is the javascript built from the production @adobe/alloy npm Library -const getProdNpmLibraryCode = () => readCache.sync(prodNpmLibraryPath, "utf8"); - -export const injectInlineScript = ClientFunction((code) => { - const scriptElement = document.createElement("script"); - - scriptElement.innerHTML = code; - document.getElementsByTagName("head")[0].appendChild(scriptElement); -}); - -const baseCodeWithCustomInstances = fs - .readFileSync(baseCodePath, "utf8") - .replace('["alloy"]', '["alloy","instance2"]'); - -const addRemoteUrlClientScript = ({ clientScripts, url, async = false }) => { - // TestCafe client scripts don't "natively" support loading a script - // from a remote URL, so we have to make our local script add another script - // element that loads Visitor from the remote server. - clientScripts.push({ - content: `document.write('')`, - }); -}; - -/** - * Produces an array of scripts that TestCafe should inject into the - * when testing Alloy int. - */ -const getFixtureClientScriptsForInt = (options) => { - const clientScripts = []; - - if (options.monitoringHooksScript) { - clientScripts.push({ - content: options.monitoringHooksScript, - }); - } - - // Useful for testing Alloy + Visitor interaction. - if (options.includeVisitorLibrary) { - addRemoteUrlClientScript({ - clientScripts, - url: REMOTE_VISITOR_LIBRARY_URL, - }); - } - - clientScripts.push({ - content: baseCodeWithCustomInstances, - }); - - // Typically the Alloy library should be loaded in head. For some tests, - // like testing command queuing, we need greater control and will - // load the Alloy library later during the test using injectAlloyDuringTest. - if (options.includeAlloyLibrary) { - // When providing client scripts to TestCafe during the fixture - // configuration process, TestCafe doesn't currently support loading scripts - // asynchronously (https://github.com/DevExpress/testcafe/issues/5612), but - // by default our customers are loading Alloy asynchronously and we would - // like to simulate that. To do so, we'll wrap our Alloy code in a - // setTimeout with a small arbitrary delay. - clientScripts.push({ - content: `setTimeout(function() {\n${getLocalAlloyCode()}\n}, 10);`, - }); - } - - if (options.includeNpmLibrary) { - clientScripts.push({ - content: getLocalNpmLibraryCode(), - }); - } - - return clientScripts; -}; - -/** - * Produces an array of scripts that TestCafe should inject into the - * when testing Alloy prod. - */ -const getFixtureClientScriptsForProd = (options) => { - const clientScripts = []; - - if (options.monitoringHooksScript) { - clientScripts.push({ - content: options.monitoringHooksScript, - }); - } - - // Useful for testing Alloy + Visitor interaction. - if (options.includeVisitorLibrary) { - addRemoteUrlClientScript({ - clientScripts, - url: REMOTE_VISITOR_LIBRARY_URL, - }); - } - - clientScripts.push({ - content: baseCodeWithCustomInstances, - }); - - // Typically the Alloy library should be loaded in head. For some tests, - // like testing command queuing, we need greater control and will - // load the Alloy library later during the test using injectAlloyDuringTest. - if (options.includeAlloyLibrary) { - addRemoteUrlClientScript({ - clientScripts, - url: remoteAlloyLibraryUrl, - async: true, - }); - } - - if (options.includeNpmLibrary) { - clientScripts.push({ - content: getProdNpmLibraryCode(), - }); - } - return clientScripts; -}; - -const getFixtureClientScriptsByEnvironment = { - int: getFixtureClientScriptsForInt, - prod: getFixtureClientScriptsForProd, -}; - -/** - * Injects Alloy into the page while running a test against Alloy int. - */ -const injectAlloyDuringTestForInt = () => - injectInlineScript(getLocalAlloyCode()); - -/** - * Injects Alloy into the page while running a test against Alloy prod. - */ -const injectAlloyDuringTestForProd = ClientFunction( - () => - new Promise((resolve) => { - const scriptElement = document.createElement("script"); - scriptElement.src = remoteAlloyLibraryUrl; - scriptElement.addEventListener("load", () => { - resolve(); - }); - document.getElementsByTagName("head")[0].appendChild(scriptElement); - }), - { - dependencies: { - remoteAlloyLibraryUrl, - }, - }, -); - -const injectAlloyDuringTestByEnvironment = { - [INTEGRATION]: injectAlloyDuringTestForInt, - [PRODUCTION]: injectAlloyDuringTestForProd, -}; - -/** - * Retrieves a clientScripts array that can be provided to a TestCafe fixture, - * which will inject script tags into the of the test page. - */ -export const getFixtureClientScripts = - getFixtureClientScriptsByEnvironment[alloyEnv]; - -/** - * Injects the Alloy library while a test is running. This is useful if you - * want to test what happens when, for example, commands are queued before - * the Alloy library finishes loading. If you use this, you'll want to set - * includeAlloyLibrary to false when configuring client scripts for the - * fixture so that Alloy isn't injected into . - */ -export const injectAlloyDuringTest = - injectAlloyDuringTestByEnvironment[alloyEnv]; diff --git a/packages/core/test/functional/helpers/createFixture/destinationRequestMock.js b/packages/core/test/functional/helpers/createFixture/destinationRequestMock.js deleted file mode 100644 index ecf569f60..000000000 --- a/packages/core/test/functional/helpers/createFixture/destinationRequestMock.js +++ /dev/null @@ -1,23 +0,0 @@ -/* -Copyright 2021 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 { RequestMock } from "testcafe"; - -// The main edge configuration we're using for testing -// has URL destinations enabled and a URL destination handle is sent -// back as part of the response from each interact endpoint request. -// So that we're not relying on a third-party server for the URL -// destination to successfully execute, we'll mock the third-party -// URL destination endpoint. -export default RequestMock() - .onRequestTo(/^https:\/\/cataas.com\//) - .respond(null, 200); diff --git a/packages/core/test/functional/helpers/createFixture/index.js b/packages/core/test/functional/helpers/createFixture/index.js deleted file mode 100644 index b5bde7d03..000000000 --- a/packages/core/test/functional/helpers/createFixture/index.js +++ /dev/null @@ -1,35 +0,0 @@ -/* -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 { TEST_PAGE as TEST_PAGE_URL } from "../constants/url.js"; -import { getFixtureClientScripts } from "./clientScripts.js"; -import destinationRequestMock from "./destinationRequestMock.js"; - -export default ({ - title = "", - url = TEST_PAGE_URL, - requestHooks = [], - monitoringHooksScript, - includeAlloyLibrary = true, - includeVisitorLibrary = false, - includeNpmLibrary = false, -}) => { - const clientScripts = getFixtureClientScripts({ - monitoringHooksScript, - includeAlloyLibrary, - includeVisitorLibrary, - includeNpmLibrary, - }); - return fixture(title) - .page(url) - .requestHooks(...requestHooks, destinationRequestMock) - .clientScripts(clientScripts); -}; diff --git a/packages/core/test/functional/helpers/createRandomEcid.js b/packages/core/test/functional/helpers/createRandomEcid.js deleted file mode 100644 index 54e9da767..000000000 --- a/packages/core/test/functional/helpers/createRandomEcid.js +++ /dev/null @@ -1,24 +0,0 @@ -/* -Copyright 2022 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 crypto from "crypto"; - -// 2 random 63 bit numbers padded with zeros to 19 digits and concatenated -export default () => { - const randomBytesBuffer = crypto.randomBytes(16); - // eslint-disable-next-line no-bitwise - randomBytesBuffer[0] &= 0x7f; - // eslint-disable-next-line no-bitwise - randomBytesBuffer[8] &= 0x7f; - const high = randomBytesBuffer.readBigInt64BE(0).toString(); - const low = randomBytesBuffer.readBigInt64BE(8).toString(); - return high.padStart(19, "0") + low.padStart(19, "0"); -}; diff --git a/packages/core/test/functional/helpers/createResponse.js b/packages/core/test/functional/helpers/createResponse.js deleted file mode 100644 index 1523b9eba..000000000 --- a/packages/core/test/functional/helpers/createResponse.js +++ /dev/null @@ -1,15 +0,0 @@ -/* -Copyright 2021 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 injectCreateResponse from "../../../src/core/injectCreateResponse.js"; - -export default injectCreateResponse({ logger: console }); diff --git a/packages/core/test/functional/helpers/createUnhandledRejectionLogger.js b/packages/core/test/functional/helpers/createUnhandledRejectionLogger.js deleted file mode 100644 index 0947fcec5..000000000 --- a/packages/core/test/functional/helpers/createUnhandledRejectionLogger.js +++ /dev/null @@ -1,83 +0,0 @@ -/* -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 } from "testcafe"; - -const containsMessageMatchingRegex = (messages, messageRegex) => { - return messages.find((message) => messageRegex.test(message)) !== undefined; -}; - -const formatFoundMessages = (messages) => { - if (!messages.length) { - return "No messages found."; - } - return `Messages found:\n${messages.join("\n")}`; -}; - -/** - * Creates an object that can used for asserting messages from unhandled - * rejections. These are promises that were rejected, but unhandled. - * - * Example: - * - * const unhandledRejectionLogger = await createUnhandledRejectionLogger(); - * await unhandledRejectionLogger.expectMessageMatching(/test/); - * await unhandledRejectionLogger.expectNoMessageMatching(/test/); - * await unhandledRejectionLogger.reset(); - */ -export default async () => { - await t.eval(() => { - window.testcafe_unhandled_rejections = []; - window.addEventListener("unhandledrejection", ({ reason }) => { - window.testcafe_unhandled_rejections.push(reason); - }); - }); - - const reset = async () => { - await t.eval(() => { - window.testcafe_unhandled_rejections.clear(); - }); - }; - - const getMessagesSinceReset = async () => { - return t.eval(() => { - return window.testcafe_unhandled_rejections || []; - }); - }; - - const expectMessageMatching = async (messageRegex) => { - const messages = await getMessagesSinceReset(); - await t - .expect(containsMessageMatchingRegex(messages, messageRegex)) - .ok( - `No unhandled rejection message was found matching ${messageRegex}. ${formatFoundMessages( - messages, - )}`, - ); - }; - - const expectNoMessageMatching = async (messageRegex) => { - const messages = await getMessagesSinceReset(); - await t - .expect(containsMessageMatchingRegex(messages, messageRegex)) - .notOk( - `An unhandled rejection message was found matching ${messageRegex} when none was expected. ${formatFoundMessages( - messages, - )}`, - ); - }; - - return { - reset, - expectMessageMatching, - expectNoMessageMatching, - }; -}; diff --git a/packages/core/test/functional/helpers/dom/addHtmlToBody.js b/packages/core/test/functional/helpers/dom/addHtmlToBody.js deleted file mode 100644 index 74d87337d..000000000 --- a/packages/core/test/functional/helpers/dom/addHtmlToBody.js +++ /dev/null @@ -1,25 +0,0 @@ -/* -Copyright 2020 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 { ClientFunction } from "testcafe"; - -export default ClientFunction((html, replace = false) => { - if (replace) { - document.body.innerHTML = ""; - } - - const div = document.createElement("div"); - div.innerHTML = html; - while (div.firstChild) { - document.body.appendChild(div.firstChild); - } -}); diff --git a/packages/core/test/functional/helpers/dom/addHtmlToHeader.js b/packages/core/test/functional/helpers/dom/addHtmlToHeader.js deleted file mode 100644 index 19579c1c8..000000000 --- a/packages/core/test/functional/helpers/dom/addHtmlToHeader.js +++ /dev/null @@ -1,20 +0,0 @@ -/* -Copyright 2020 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 { ClientFunction } from "testcafe"; - -export default ClientFunction((html) => { - const head = document.createElement("head"); - head.innerHTML = html; - while (head.firstChild) { - document.head.appendChild(head.firstChild); - } -}); diff --git a/packages/core/test/functional/helpers/flushPromiseChains.js b/packages/core/test/functional/helpers/flushPromiseChains.js deleted file mode 100644 index 203292e34..000000000 --- a/packages/core/test/functional/helpers/flushPromiseChains.js +++ /dev/null @@ -1,32 +0,0 @@ -/* -Copyright 2019 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 { ClientFunction } from "testcafe"; - -/** - * Returns a promise that will be resolved after all outstanding promise chains - * have been flushed. This assumes (1) that the promise chains to be flushed - * resolve their promises promptly (rather than doing something like - * setTimeout(..., 100) somewhere in the chain) and (2) that the chains - * are no longer than 10 promises long. - * @returns {Promise} - */ -export default ClientFunction(() => { - let promise; - - for (let i = 0; i < 10; i += 1) { - promise = promise - ? promise.then(() => Promise.resolve()) - : Promise.resolve(); - } - - return promise; -}); diff --git a/packages/core/test/functional/helpers/getBaseConfig.js b/packages/core/test/functional/helpers/getBaseConfig.js deleted file mode 100644 index 6073ee065..000000000 --- a/packages/core/test/functional/helpers/getBaseConfig.js +++ /dev/null @@ -1,30 +0,0 @@ -/* -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 DATASTREAM_ID from "./constants/datastreamId.js"; -import edgeDomainThirdParty from "./constants/configParts/edgeDomainThirdParty.js"; - -const edgeBasePath = process.env.EDGE_BASE_PATH; - -export default (orgId, configId = DATASTREAM_ID) => { - const config = { - datastreamId: configId, - orgId: orgId || "5BFE274A5F6980A50A495C08@AdobeOrg", - // Default `edgeDomain` to 3rd party; override in specific test if needed. - ...edgeDomainThirdParty, - }; - - if (edgeBasePath) { - config.edgeBasePath = edgeBasePath; - } - - return config; -}; diff --git a/packages/core/test/functional/helpers/isUserAgentClientHintsSupported.js b/packages/core/test/functional/helpers/isUserAgentClientHintsSupported.js deleted file mode 100644 index 0002cae97..000000000 --- a/packages/core/test/functional/helpers/isUserAgentClientHintsSupported.js +++ /dev/null @@ -1,15 +0,0 @@ -/* -Copyright 2022 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 { ClientFunction } from "testcafe"; - -export default ClientFunction(() => "userAgentData" in navigator); diff --git a/packages/core/test/functional/helpers/networkLogger/awaitRequestResponse.js b/packages/core/test/functional/helpers/networkLogger/awaitRequestResponse.js deleted file mode 100644 index 70e05b1da..000000000 --- a/packages/core/test/functional/helpers/networkLogger/awaitRequestResponse.js +++ /dev/null @@ -1,21 +0,0 @@ -/* -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. -*/ - -export default async (request) => - new Promise((r) => { - const t = setInterval(() => { - if (request.response) { - clearInterval(t); - r(); - } - }, 10); - }); diff --git a/packages/core/test/functional/helpers/networkLogger/getResponseBody.js b/packages/core/test/functional/helpers/networkLogger/getResponseBody.js deleted file mode 100644 index ad0751603..000000000 --- a/packages/core/test/functional/helpers/networkLogger/getResponseBody.js +++ /dev/null @@ -1,38 +0,0 @@ -/* -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. -*/ - -const zlib = require("zlib"); - -const getResponseBody = (request) => { - const encoding = request.response.headers["content-encoding"]; - const bodyBuffer = request.response.body; - let decompressedBody = bodyBuffer; - - // Chrome responses are getting here already decompressed. - // For Firefox, we need to decompress the body. - try { - // eslint-disable-next-line default-case - switch (encoding) { - case "deflate": - decompressedBody = zlib.inflateRawSync(bodyBuffer); - break; - case "gzip": - decompressedBody = zlib.gunzipSync(bodyBuffer); - break; - } - // eslint-disable-next-line no-empty - } catch {} - - return decompressedBody.toString(); -}; - -export default getResponseBody; diff --git a/packages/core/test/functional/helpers/networkLogger/getReturnedEcid.js b/packages/core/test/functional/helpers/networkLogger/getReturnedEcid.js deleted file mode 100644 index 8cb715040..000000000 --- a/packages/core/test/functional/helpers/networkLogger/getReturnedEcid.js +++ /dev/null @@ -1,26 +0,0 @@ -/* -Copyright 2022 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 getResponseBody from "./getResponseBody.js"; -import createResponse from "../createResponse.js"; - -export default (request) => { - const response = JSON.parse(getResponseBody(request)); - const payloads = createResponse({ content: response }).getPayloadsByType( - "identity:result", - ); - const ecidPayload = payloads.filter( - (payload) => payload.namespace.code === "ECID", - )[0]; - - return ecidPayload.id; -}; diff --git a/packages/core/test/functional/helpers/networkLogger/index.js b/packages/core/test/functional/helpers/networkLogger/index.js deleted file mode 100644 index 1252e42f2..000000000 --- a/packages/core/test/functional/helpers/networkLogger/index.js +++ /dev/null @@ -1,148 +0,0 @@ -/* -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 { RequestLogger } from "testcafe"; - -const networkLoggerOptions = { - logRequestHeaders: true, - logRequestBody: true, - logResponseBody: true, - stringifyResponseBody: false, - stringifyRequestBody: true, - logResponseHeaders: true, -}; - -const createRequestLogger = (endpoint) => { - return RequestLogger(endpoint, networkLoggerOptions); -}; - -const createNetworkLogger = () => { - const edgeEndpoint = /v1\/(interact|collect)\?configId=/; - const edgeCollectEndpoint = /v1\/collect\?configId=/; - const edgeInteractEndpoint = /v1\/interact\?configId=/; - const setConsentEndpoint = /v1\/privacy\/set-consent\?configId=/; - const acquireEndpoint = /v1\/identity\/acquire\?configId=/; - const targetDeliveryEndpoint = /rest\/v1\/delivery\?client=/; - const targetMboxJsonEndpoint = /m2\/unifiedjsqeonly\/mbox\/json\?mbox=/; - // media endpoints - const playEndpoint = /va\/v1\/play/; - const pauseEndpoint = /va\/v1\/pauseStart/; - const pingEndpoint = /va\/v1\/ping/; - const adBreakCompleteEndpoint = /va\/v1\/adBreakComplete/; - const adBreakStartEndpoint = /va\/v1\/adBreakStart/; - const adCompleteEndpoint = /va\/v1\/adComplete/; - const adSkipEndpoint = /va\/v1\/adSkip/; - const adStartEndpoint = /va\/v1\/adStart/; - const bitrateChangeEndpoint = /va\/v1\/bitrateChange/; - const bufferStartEndpoint = /va\/v1\/bufferStart/; - const chapterCompleteEndpoint = /va\/v1\/chapterComplete/; - const chapterSkipEndpoint = /va\/v1\/chapterSkip/; - const chapterStartEndpoint = /va\/v1\/chapterStart/; - const errorEndpoint = /va\/v1\/error/; - const sessionCompleteEndpoint = /va\/v1\/sessionComplete/; - const sessionEndEndpoint = /va\/v1\/sessionEnd/; - const statesUpdateEndpoint = /va\/v1\/statesUpdate/; - - const edgeEndpointLogs = createRequestLogger(edgeEndpoint); - const edgeCollectEndpointLogs = createRequestLogger(edgeCollectEndpoint); - const edgeInteractEndpointLogs = createRequestLogger(edgeInteractEndpoint); - const setConsentEndpointLogs = createRequestLogger(setConsentEndpoint); - const acquireEndpointLogs = createRequestLogger(acquireEndpoint); - const targetDeliveryEndpointLogs = createRequestLogger( - targetDeliveryEndpoint, - ); - const targetMboxJsonEndpointLogs = createRequestLogger( - targetMboxJsonEndpoint, - ); - // media endpoint loggers - const mediaPlayEndpointLogs = createRequestLogger(playEndpoint); - const mediaPauseEndpointLogs = createRequestLogger(pauseEndpoint); - const pingEndpointLogs = createRequestLogger(pingEndpoint); - const adBreakCompleteEndpointLogs = createRequestLogger( - adBreakCompleteEndpoint, - ); - const adBreakStartEndpointLogs = createRequestLogger(adBreakStartEndpoint); - const adCompleteEndpointLogs = createRequestLogger(adCompleteEndpoint); - const adSkipEndpointLogs = createRequestLogger(adSkipEndpoint); - const adStartEndpointLogs = createRequestLogger(adStartEndpoint); - const bitrateChangeEndpointLogs = createRequestLogger(bitrateChangeEndpoint); - const bufferStartEndpointLogs = createRequestLogger(bufferStartEndpoint); - const chapterCompleteEndpointLogs = createRequestLogger( - chapterCompleteEndpoint, - ); - const chapterSkipEndpointLogs = createRequestLogger(chapterSkipEndpoint); - const chapterStartEndpointLogs = createRequestLogger(chapterStartEndpoint); - const errorEndpointLogs = createRequestLogger(errorEndpoint); - const sessionCompleteEndpointLogs = createRequestLogger( - sessionCompleteEndpoint, - ); - const sessionEndEndpointLogs = createRequestLogger(sessionEndEndpoint); - const statesUpdateEndpointLogs = createRequestLogger(statesUpdateEndpoint); - - const clearLogs = async () => { - await edgeEndpointLogs.clear(); - await edgeCollectEndpointLogs.clear(); - await edgeInteractEndpointLogs.clear(); - await setConsentEndpointLogs.clear(); - await acquireEndpointLogs.clear(); - await targetDeliveryEndpointLogs.clear(); - await targetMboxJsonEndpointLogs.clear(); - await mediaPlayEndpointLogs.clear(); - await mediaPauseEndpointLogs.clear(); - await pingEndpointLogs.clear(); - await adBreakCompleteEndpointLogs.clear(); - await adBreakStartEndpointLogs.clear(); - await adCompleteEndpointLogs.clear(); - await adSkipEndpointLogs.clear(); - await adStartEndpointLogs.clear(); - await bitrateChangeEndpointLogs.clear(); - await bufferStartEndpointLogs.clear(); - await chapterCompleteEndpointLogs.clear(); - await chapterSkipEndpointLogs.clear(); - await chapterStartEndpointLogs.clear(); - await errorEndpointLogs.clear(); - await sessionCompleteEndpointLogs.clear(); - await sessionEndEndpointLogs.clear(); - await statesUpdateEndpointLogs.clear(); - }; - - return { - edgeEndpointLogs, - // Before using edgeCollectEndpointLogs in a test, check to see if you - // should be using the createCollectEndpointAssertion.js module instead. - edgeCollectEndpointLogs, - edgeInteractEndpointLogs, - setConsentEndpointLogs, - acquireEndpointLogs, - targetDeliveryEndpointLogs, - targetMboxJsonEndpointLogs, - mediaPlayEndpointLogs, - mediaPauseEndpointLogs, - pingEndpointLogs, - adBreakCompleteEndpointLogs, - adBreakStartEndpointLogs, - adCompleteEndpointLogs, - adSkipEndpointLogs, - adStartEndpointLogs, - bitrateChangeEndpointLogs, - bufferStartEndpointLogs, - chapterCompleteEndpointLogs, - chapterSkipEndpointLogs, - chapterStartEndpointLogs, - errorEndpointLogs, - sessionCompleteEndpointLogs, - sessionEndEndpointLogs, - statesUpdateEndpointLogs, - clearLogs, - }; -}; - -export default createNetworkLogger; diff --git a/packages/core/test/functional/helpers/npmPackageLocal.js b/packages/core/test/functional/helpers/npmPackageLocal.js deleted file mode 100644 index b583123d3..000000000 --- a/packages/core/test/functional/helpers/npmPackageLocal.js +++ /dev/null @@ -1,15 +0,0 @@ -/* -Copyright 2020 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 { createInstance } from "../../../src/index.js"; - -window.alloyCreateInstance = createInstance; diff --git a/packages/core/test/functional/helpers/npmPackageProd.js b/packages/core/test/functional/helpers/npmPackageProd.js deleted file mode 100644 index 7a7048adf..000000000 --- a/packages/core/test/functional/helpers/npmPackageProd.js +++ /dev/null @@ -1,17 +0,0 @@ -/* -Copyright 2020 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. -*/ - -// eslint-disable-next-line import/no-unresolved -// FIXME: Self-dependency is broken in monorepo, so this does not currently work. -import { createInstance } from "@adobe/alloy"; - -window.alloyCreateInstance = createInstance; diff --git a/packages/core/test/functional/helpers/optIn/createMockOptIn.js b/packages/core/test/functional/helpers/optIn/createMockOptIn.js deleted file mode 100644 index 912412cc3..000000000 --- a/packages/core/test/functional/helpers/optIn/createMockOptIn.js +++ /dev/null @@ -1,31 +0,0 @@ -/* -Copyright 2020 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 { ClientFunction } from "testcafe"; - -export default ClientFunction((approved) => { - window.adobe = { - optIn: { - fetchPermissions(callback) { - setTimeout(() => { - callback(); - }, 0); - }, - isApproved() { - return approved; - }, - Categories: { - ECID: "ecid", - }, - }, - }; -}); diff --git a/packages/core/test/functional/helpers/preventLinkNavigation.js b/packages/core/test/functional/helpers/preventLinkNavigation.js deleted file mode 100644 index df4bff1cc..000000000 --- a/packages/core/test/functional/helpers/preventLinkNavigation.js +++ /dev/null @@ -1,24 +0,0 @@ -/* -Copyright 2021 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 { ClientFunction } from "testcafe"; - -/** - * Prevents links from navigating the user. This can be particularly - * useful in tests that are asserting requests that would typically - * occur as a user navigates away from the page. - */ -export default ClientFunction(() => { - document.addEventListener("click", (event) => { - event.preventDefault(); - }); -}); diff --git a/packages/core/test/functional/helpers/reloadPage.js b/packages/core/test/functional/helpers/reloadPage.js deleted file mode 100644 index e62ef7b82..000000000 --- a/packages/core/test/functional/helpers/reloadPage.js +++ /dev/null @@ -1,56 +0,0 @@ -/* -Copyright 2020 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 { RELOAD_PAGE as RELOAD_PAGE_URL } from "./constants/url.js"; - -const getLocalStorageEntries = ClientFunction(() => { - const entries = Object.keys(window.localStorage) - // It seems that TestCafe modifies localStorage in such a way that - // Object.keys() returns not just the entry names, but also some methods, - // so we have to filter down to only those keys that are actual - // storage entries. - .filter((key) => localStorage.getItem(key) !== null) - .reduce((memo, entryName) => { - memo[entryName] = localStorage[entryName]; - return memo; - }, {}); - return entries; -}); - -const setLocalStorageEntries = ClientFunction((entries) => { - Object.keys(entries).forEach((entryName) => { - localStorage.setItem(entryName, entries[entryName]); - }); -}); - -const getCurrentUrl = ClientFunction(() => document.location.href); - -export default async (newQueryString = "") => { - const currentUrl = new URL(await getCurrentUrl()); - currentUrl.search = newQueryString; - // navigateTo waits for the server to respond after a redirect occurs, - // which is why we use it instead of just calling document.location.reload() - // in our client function. - // TestCafe + Safari have an issue where local storage is cleared when using - // t.navigateTo(), which is why we have to retrieve local storage entries - // and then restore them after navigation. - // https://github.com/DevExpress/testcafe/issues/5992 - // Also, we have to navigate to a different page and then back to the current page, - // because if we just tried to navigate to the same page we're on, TestCafe - // would hang in Safari (at least). - const localStorageEntries = await getLocalStorageEntries(); - // We could navigate to any other page and then back again. - await t.navigateTo(RELOAD_PAGE_URL); - await t.navigateTo(currentUrl.toString()); - await setLocalStorageEntries(localStorageEntries); -}; diff --git a/packages/core/test/functional/helpers/requestHooks/demdexBlockerMock.js b/packages/core/test/functional/helpers/requestHooks/demdexBlockerMock.js deleted file mode 100644 index d45657a5a..000000000 --- a/packages/core/test/functional/helpers/requestHooks/demdexBlockerMock.js +++ /dev/null @@ -1,23 +0,0 @@ -/* -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 { RequestMock } from "testcafe"; - -// Mock that fails demdex requests -export default RequestMock() - .onRequestTo((request) => request.url.includes("demdex.net")) - .respond((req, res) => { - res.statusCode = 500; - res.headers = { - "content-type": "application/json", - }; - return ""; - }); diff --git a/packages/core/test/functional/helpers/requestHooks/failOnceHook.js b/packages/core/test/functional/helpers/requestHooks/failOnceHook.js deleted file mode 100644 index c9e33db96..000000000 --- a/packages/core/test/functional/helpers/requestHooks/failOnceHook.js +++ /dev/null @@ -1,41 +0,0 @@ -/* -Copyright 2020 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 { RequestHook } from "testcafe"; - -/** - * Useful for determining if requests were sent sequentially - * (a response from a request is received before the next request - * is sent). - */ -export default class FailOnceHook extends RequestHook { - constructor(...args) { - super(...args); - this.numRequests = 0; - } - - async onRequest() { - this.numRequests += 1; - } - - async onResponse() { - this.outstandingRequest = false; - } - - haveRequestsBeenSequential() { - return this.allRequestsSequential; - } - - getNumRequests() { - return this.numRequests; - } -} diff --git a/packages/core/test/functional/helpers/requestHooks/sequentialHook.js b/packages/core/test/functional/helpers/requestHooks/sequentialHook.js deleted file mode 100644 index cab7225e9..000000000 --- a/packages/core/test/functional/helpers/requestHooks/sequentialHook.js +++ /dev/null @@ -1,47 +0,0 @@ -/* -Copyright 2020 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 { RequestHook } from "testcafe"; - -/** - * Useful for determining if requests were sent sequentially - * (a response from a request is received before the next request - * is sent). - */ -export default class SequentialHook extends RequestHook { - constructor(...args) { - super(...args); - this.numRequests = 0; - this.outstandingRequest = false; - this.allRequestsSequential = true; - } - - async onRequest() { - this.numRequests += 1; - if (this.outstandingRequest) { - this.allRequestsSequential = false; - } - this.outstandingRequest = true; - } - - async onResponse() { - this.outstandingRequest = false; - } - - haveRequestsBeenSequential() { - return this.allRequestsSequential; - } - - getNumRequests() { - return this.numRequests; - } -} diff --git a/packages/core/test/functional/helpers/sendBeaconMock.js b/packages/core/test/functional/helpers/sendBeaconMock.js deleted file mode 100644 index 47202be4a..000000000 --- a/packages/core/test/functional/helpers/sendBeaconMock.js +++ /dev/null @@ -1,48 +0,0 @@ -/* -Copyright 2020 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 { ClientFunction } from "testcafe"; - -const mock = ClientFunction(() => { - const nativeSendBeacon = window.navigator.sendBeacon.bind(window.navigator); - window.navigator.sendBeacon = (...args) => { - const sendBeaconCallCount = Number( - sessionStorage.getItem("sendBeaconCallCount") || 0, - ); - sessionStorage.setItem("sendBeaconCallCount", sendBeaconCallCount + 1); - return nativeSendBeacon(...args); - }; -}); - -const getCallCount = ClientFunction(() => { - return Number(sessionStorage.getItem("sendBeaconCallCount") || 0); -}); - -const reset = ClientFunction(() => { - sessionStorage.removeItem("sendBeaconCallCount"); -}); - -/** - * Mocks and calls through to the native sendBeacon API. Useful for - * determining whether sendBeacon was used to make a network request. - * This is typically better than using a network logger because sendBeacon, - * at least in some browsers, asynchronously sends the request some time - * after sendBeacon is called. This would make it tricky to assert, for example, - * that a network request *wasn't* sent using sendBeacon because we would - * have to wait an arbitrary time period before checking the network logger - * to see that no requests were made to the collect endpoint. - */ -export default { - mock, - getCallCount, - reset, -}; diff --git a/packages/core/test/functional/helpers/setLegacyIdentityCookie.js b/packages/core/test/functional/helpers/setLegacyIdentityCookie.js deleted file mode 100644 index 8ef4d39f2..000000000 --- a/packages/core/test/functional/helpers/setLegacyIdentityCookie.js +++ /dev/null @@ -1,24 +0,0 @@ -/* -Copyright 2020 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 } from "testcafe"; - -export default async (orgId) => { - const encodedOrgId = encodeURIComponent(orgId); - await t.setCookies({ - name: `AMCV_${encodedOrgId}`, - value: - "77933605%7CMCIDTS%7C18290%7CMCMID%7C16908443662402872073525706953453086963%7CMCAAMLH-1580857889%7C9%7CMCAAMB-1580857889%7CRKhpRz8krg2tLO6pguXWp5olkAcUniQYPHaMWWgdJ3xzPWQmdj0y%7CMCOPTOUT-1580260289s%7CNONE%7CvVersion%7C4.5.1", - domain: "alloyio.com", - path: "/", - }); -}; diff --git a/packages/core/test/functional/helpers/visitorService/getVisitorEcid.js b/packages/core/test/functional/helpers/visitorService/getVisitorEcid.js deleted file mode 100644 index 85200e5b5..000000000 --- a/packages/core/test/functional/helpers/visitorService/getVisitorEcid.js +++ /dev/null @@ -1,22 +0,0 @@ -/* -Copyright 2020 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 { ClientFunction } from "testcafe"; - -export default ClientFunction((orgId) => { - return new Promise((resolve) => { - const visitor = window.Visitor.getInstance(orgId, {}); - visitor.getMarketingCloudVisitorID((ecid) => { - resolve(ecid); - }, true); - }); -}); diff --git a/packages/core/test/functional/specs/Audiences/C12411.js b/packages/core/test/functional/specs/Audiences/C12411.js deleted file mode 100644 index 79d660293..000000000 --- a/packages/core/test/functional/specs/Audiences/C12411.js +++ /dev/null @@ -1,56 +0,0 @@ -/* -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 { RequestLogger, t } from "testcafe"; -import createNetworkLogger from "../../helpers/networkLogger/index.js"; -import createFixture from "../../helpers/createFixture/index.js"; -import { orgMainConfigMain } from "../../helpers/constants/configParts/index.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; - -const networkLogger = createNetworkLogger(); - -const networkLoggerConfig = { - logRequestBody: true, - stringifyRequestBody: true, -}; - -const destinationLogger = RequestLogger( - "https://cataas.com/cat", - networkLoggerConfig, -); - -createFixture({ - title: - "C12411 Response should return URL destinations if turned on in Blackbird", - requestHooks: [networkLogger.edgeEndpointLogs, destinationLogger], -}); - -test.meta({ - ID: "C12411", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -// This test is skipped because there's a bug in TestCafe where the request logger doesn't -// log the request of the URL destination image if the image is loaded inside an iframe. -// The image is loaded inside an iframe because hideReferrer is set to true for the -// URL destination. We could fix this test by setting hideReferrer to false so that -// the image is loaded outside an iframe, but there seems to be another bug at or -// behind Konductor preventing us from doing so. -// https://github.com/DevExpress/testcafe/issues/6060 -// https://jira.corp.adobe.com/browse/PDCL-4709 -test.skip("C12411 Response should return URL destinations if turned on in Blackbird", async () => { - const alloy = createAlloyProxy(); - await alloy.configure(orgMainConfigMain); - await alloy.sendEvent(); - - await t.expect(destinationLogger.requests.length > 0).eql(true); -}); diff --git a/packages/core/test/functional/specs/Audiences/C12412.js b/packages/core/test/functional/specs/Audiences/C12412.js deleted file mode 100644 index 7895402c7..000000000 --- a/packages/core/test/functional/specs/Audiences/C12412.js +++ /dev/null @@ -1,74 +0,0 @@ -/* -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 createNetworkLogger from "../../helpers/networkLogger/index.js"; -import createFixture from "../../helpers/createFixture/index.js"; -import { - compose, - orgMainConfigMain, - debugEnabled, -} from "../../helpers/constants/configParts/index.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; -import createConsoleLogger from "../../helpers/consoleLogger/index.js"; - -const networkLogger = createNetworkLogger(); - -createFixture( - `C12412 Response should return Cookie destinations if turned on in Blackbird`, - { - requestHooks: [networkLogger.edgeEndpointLogs], - meta: { - ID: "C12412", - SEVERITY: "P0", - TEST_RUN: "Regression", - }, - }, -); - -const getDocumentCookie = ClientFunction(() => document.cookie); - -test(`Verify cookie destinations are returned in the response when turned on in Blackbird`, async () => { - const logger = await createConsoleLogger(); - const alloy = createAlloyProxy(); - - await alloy.configure(compose(orgMainConfigMain, debugEnabled)); - await alloy.sendEvent(); - - await t.expect(getDocumentCookie()).contains("C12412=test%3DC12412"); - - const logs = await logger.info.getMessagesSinceReset(); - const setCookieAttributes = logs - .filter( - (message) => message.length === 3 && message[1] === `Setting cookie`, - ) - .map((message) => message[2]) - .filter((cookieSettings) => cookieSettings.name === "C12412"); - - await t.expect(setCookieAttributes.length).eql(1); - await t.expect(setCookieAttributes[0].sameSite).eql("none"); - await t.expect(setCookieAttributes[0].secure).eql(true); -}); - -test(`Verify cookie is set on the / path `, async () => { - const alloy = createAlloyProxy(); - - await alloy.configure(compose(orgMainConfigMain, debugEnabled)); - await alloy.sendEvent(); - - const cookies = await t.getCookies("C12412"); - - // In Firefox, the t.getCookies method returns an empty array even if the cookie is present. - // The if condition below is to handle this issue. - if (cookies.length > 0) { - await t.expect(cookies[0].path).eql("/"); - } -}); diff --git a/packages/core/test/functional/specs/Audiences/C31436.js b/packages/core/test/functional/specs/Audiences/C31436.js deleted file mode 100644 index faa72529b..000000000 --- a/packages/core/test/functional/specs/Audiences/C31436.js +++ /dev/null @@ -1,57 +0,0 @@ -/* -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 { RequestLogger, t } from "testcafe"; -import createNetworkLogger from "../../helpers/networkLogger/index.js"; -import createFixture from "../../helpers/createFixture/index.js"; -import { orgMainConfigMain } from "../../helpers/constants/configParts/index.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; - -const networkLogger = createNetworkLogger(); - -const networkLoggerConfig = { - logRequestBody: true, - stringifyRequestBody: true, -}; - -const destinationLogger = RequestLogger( - "https://cataas.com/cat/cute", - networkLoggerConfig, -); - -createFixture({ - title: "C31436 Qualify for URL destinations via XDM Data.", - requestHooks: [networkLogger.edgeEndpointLogs, destinationLogger], -}); - -test.meta({ - ID: "C31436", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -// This test is skipped because there's a bug in TestCafe where the request logger doesn't -// log the request of the URL destination image if the image is loaded inside an iframe. -// The image is loaded inside an iframe because hideReferrer is set to true for the -// URL destination. We could fix this test by setting hideReferrer to false so that -// the image is loaded outside an iframe, but there seems to be another bug at or -// behind Konductor preventing us from doing so. -// https://github.com/DevExpress/testcafe/issues/6060 -// https://jira.corp.adobe.com/browse/PDCL-4709 -test.skip("C31436 Qualify for URL destinations via XDM Data.", async () => { - const alloy = createAlloyProxy(); - await alloy.configure(orgMainConfigMain); - await alloy.sendEvent({ - xdm: { web: { webPageDetails: { name: "C31436" } } }, - }); - - await t.expect(destinationLogger.requests.length).eql(1); -}); diff --git a/packages/core/test/functional/specs/CNAME/C148846.js b/packages/core/test/functional/specs/CNAME/C148846.js deleted file mode 100644 index b6e97b96a..000000000 --- a/packages/core/test/functional/specs/CNAME/C148846.js +++ /dev/null @@ -1,101 +0,0 @@ -/* -Copyright 2020 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 } from "testcafe"; -import createNetworkLogger from "../../helpers/networkLogger/index.js"; -import createFixture from "../../helpers/createFixture/index.js"; -import { - compose, - edgeDomainFirstParty, - orgMainConfigMain, -} from "../../helpers/constants/configParts/index.js"; -import { FIRST_PARTY_DOMAIN } from "../../helpers/constants/domain.js"; -import getResponseBody from "../../helpers/networkLogger/getResponseBody.js"; -import createResponse from "../../helpers/createResponse.js"; -import areThirdPartyCookiesSupported from "../../helpers/areThirdPartyCookiesSupported.js"; -import { MAIN_IDENTITY_COOKIE_NAME } from "../../helpers/constants/cookies.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; - -const demdexUrlRegex = /\.demdex\.net/; - -const getUrlFor = (requestLogger) => requestLogger.request.url; - -const config = compose(orgMainConfigMain, edgeDomainFirstParty); - -test.meta({ - ID: "C148846", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -const networkLogger = createNetworkLogger(); -createFixture({ - title: "C148846 - Setting edgeDomain to CNAME", - requestHooks: [networkLogger.edgeInteractEndpointLogs], -}); - -test("C148846 - Setting edgeDomain to CNAME results in server calls to this CNAME", async () => { - const alloy = createAlloyProxy(); - await alloy.configure(config); - await alloy.sendEvent(); - await alloy.sendEvent(); - - const firstRequest = networkLogger.edgeInteractEndpointLogs.requests[0]; - // const secondRequest = networkLogger.edgeInteractEndpointLogs.requests[1]; - - const responseForDemdexRequest = JSON.parse(getResponseBody(firstRequest)); - // const responseForCnameRequest = JSON.parse(getResponseBody(secondRequest)); - - const alloyDemdexResponse = createResponse({ - content: responseForDemdexRequest, - }); - const demdexStateHandle = - alloyDemdexResponse.getPayloadsByType("state:store"); - - // const alloyCnameResponse = createResponse({ content: responseForCnameRequest }); - // const cnameStateHandle = alloyCnameResponse.getPayloadsByType("state:store"); - - const demdexResponseContainsIdentityCookie = demdexStateHandle.find((h) => - h.key.includes(MAIN_IDENTITY_COOKIE_NAME), - ); - - const urlForFirstRequest = getUrlFor(firstRequest); - // const hostForSecondRequest = getHostFor(secondRequest); - - if (areThirdPartyCookiesSupported()) { - await t.expect(urlForFirstRequest).match(demdexUrlRegex); - // await t.expect(hostForSecondRequest).contains(FIRST_PARTY_DOMAIN); - - // Expects the demdex response to contain Konductor state. - // Expects the demdex state to contain the identity cookie. - await t.expect(demdexStateHandle.length).gte(0); - await t.expect(demdexResponseContainsIdentityCookie).ok(); - } else { - await t.expect(urlForFirstRequest).contains(FIRST_PARTY_DOMAIN); - // await t.expect(hostForSecondRequest).contains(FIRST_PARTY_DOMAIN); - } - - // We don't believe these assertions are valid. When running this test locally on Firefox, - // Testcafe adds an additional identifier to the cookie. - - // Expects the CNAME request header to contain the Konductor state cookies. - // Expects the CNAME response body to not contain the Konductor state. - // Expects the CNAME response header to contain the Konductor state. - // await t - // .expect(secondRequest.request.headers.cookie) - // .contains(MAIN_IDENTITY_COOKIE_NAME); - // await t.expect(cnameStateHandle.length).eql(0); - // await t.expect(secondRequest.response.headers["set-cookie"]).ok(); - // await t - // .expect(secondRequest.response.headers["set-cookie"][0]) - // .contains(MAIN_IDENTITY_COOKIE_NAME); -}); diff --git a/packages/core/test/functional/specs/Command Logic/C11634155.js b/packages/core/test/functional/specs/Command Logic/C11634155.js deleted file mode 100644 index e936a4c02..000000000 --- a/packages/core/test/functional/specs/Command Logic/C11634155.js +++ /dev/null @@ -1,73 +0,0 @@ -/* -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 { - compose, - debugEnabled, - orgMainConfigMain, -} from "../../helpers/constants/configParts/index.js"; -import createFixture from "../../helpers/createFixture/index.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; -import createNetworkLogger from "../../helpers/networkLogger/index.js"; -import { responseStatus } from "../../helpers/assertions/index.js"; -import createConsoleLogger from "../../helpers/consoleLogger/index.js"; - -const networkLogger = createNetworkLogger(); -const config = compose(orgMainConfigMain, debugEnabled, { - edgeConfigId: orgMainConfigMain.datastreamId, -}); -delete config.datastreamId; - -createFixture({ - title: "C11634155: Deprecates options like edgeConfigId and warns with use", - requestHooks: [networkLogger.edgeEndpointLogs], -}); - -test.meta({ - ID: "C11634155", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -test("Test C11634155: Deprecates options like edgeConfigId and warns with use", async () => { - const logger = await createConsoleLogger(); - - const alloy = createAlloyProxy(); - await alloy.configure(config); - - await logger.warn.expectMessageMatching( - /The field 'edgeConfigId' is deprecated./, - ); -}); - -test("Test C11634155: Deprecates options like edgeConfigId and warns when both are used", async () => { - const logger = await createConsoleLogger(); - const configWithBoth = { ...config, datastreamId: config.edgeConfigId }; - - const alloy = createAlloyProxy(); - await alloy.configure(configWithBoth); - - await logger.warn.expectMessageMatching( - /The field 'edgeConfigId' is deprecated./, - ); -}); - -test("Test C11634155: When specifying a deprecated option like edgeConfigId, it uses the specified alternative, datastreamId", async (t) => { - const alloy = createAlloyProxy(); - await alloy.configureAsync(config); - - await alloy.sendEvent({}); - - await responseStatus(networkLogger.edgeEndpointLogs.requests, [200, 207]); - await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(1); - const { url } = networkLogger.edgeEndpointLogs.requests[0].request; - await t.expect(url).contains(config.edgeConfigId); -}); diff --git a/packages/core/test/functional/specs/Command Logic/C13816.js b/packages/core/test/functional/specs/Command Logic/C13816.js deleted file mode 100644 index 98166a393..000000000 --- a/packages/core/test/functional/specs/Command Logic/C13816.js +++ /dev/null @@ -1,35 +0,0 @@ -/* -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 createAlloyProxy from "../../helpers/createAlloyProxy.js"; -import createFixture from "../../helpers/createFixture/index.js"; - -createFixture({ - title: "C13816: Throws error when configure has no options", -}); - -test.meta({ - ID: "C13816", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -test("Test C13816: Throws error when configure has no options", async (t) => { - const alloy = createAlloyProxy(); - const configureErrorMessage = await alloy.configureErrorMessage(); - - await t - .expect(configureErrorMessage) - .ok("Configure didn't throw an exception."); - await t.expect(configureErrorMessage).contains("orgId"); - await t.expect(configureErrorMessage).contains("datastreamId"); - await t.expect(configureErrorMessage).contains("documentation"); -}); diff --git a/packages/core/test/functional/specs/Command Logic/C13817.js b/packages/core/test/functional/specs/Command Logic/C13817.js deleted file mode 100644 index 9560e52a7..000000000 --- a/packages/core/test/functional/specs/Command Logic/C13817.js +++ /dev/null @@ -1,30 +0,0 @@ -/* -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 createAlloyProxy from "../../helpers/createAlloyProxy.js"; -import createFixture from "../../helpers/createFixture/index.js"; - -createFixture({ - title: "C13817: Throws error when running command after bad configure", -}); - -test.meta({ - ID: "C13817", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -test("Test C13817: Throws error when running command after bad configure", async (t) => { - const alloy = createAlloyProxy(); - await alloy.configureErrorMessage(); - const eventErrorMessage = await alloy.sendEventErrorMessage(); - await t.expect(eventErrorMessage).contains("configured"); -}); diff --git a/packages/core/test/functional/specs/Command Logic/C13818.js b/packages/core/test/functional/specs/Command Logic/C13818.js deleted file mode 100644 index e446da230..000000000 --- a/packages/core/test/functional/specs/Command Logic/C13818.js +++ /dev/null @@ -1,63 +0,0 @@ -/* -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 { RequestLogger, ClientFunction } from "testcafe"; -import createFixture from "../../helpers/createFixture/index.js"; - -import { - orgMainConfigMain, - orgAltConfigAlt, -} from "../../helpers/constants/configParts/index.js"; - -const networkLoggerConfig = { - logRequestBody: true, - stringifyRequestBody: true, -}; -const networkLogger1 = RequestLogger( - new RegExp( - `v1\\/(interact|collect)\\?configId=${orgMainConfigMain.datastreamId}`, - ), - networkLoggerConfig, -); -const networkLogger2 = RequestLogger( - new RegExp( - `v1\\/(interact|collect)\\?configId=${orgAltConfigAlt.datastreamId}`, - ), - networkLoggerConfig, -); - -createFixture({ - title: - "C13818: Changing the options object after configure doesn't change the computed config", - requestHooks: [networkLogger1, networkLogger2], -}); - -test.meta({ - ID: "C13818", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -const apiCalls = ClientFunction((configObject, alternateConfigObject) => { - return window.alloy("configure", configObject).then(() => { - Object.keys(alternateConfigObject).forEach((key) => { - configObject[key] = alternateConfigObject[key]; - }); - return window.alloy("sendEvent"); - }); -}); - -test("Test C13818: Changing the options object after configure doesn't change the computed config", async (t) => { - await apiCalls(orgMainConfigMain, orgAltConfigAlt); - - await t.expect(networkLogger1.requests.length).eql(1); - await t.expect(networkLogger2.requests.length).eql(0); -}); diff --git a/packages/core/test/functional/specs/Command Logic/C13819.js b/packages/core/test/functional/specs/Command Logic/C13819.js deleted file mode 100644 index 56a12c396..000000000 --- a/packages/core/test/functional/specs/Command Logic/C13819.js +++ /dev/null @@ -1,47 +0,0 @@ -/* -Copyright 2021 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 { ClientFunction } from "testcafe"; -import { - compose, - orgMainConfigMain, -} from "../../helpers/constants/configParts/index.js"; -import createFixture from "../../helpers/createFixture/index.js"; -import configureAlloyInstance from "../../helpers/configureAlloyInstance/index.js"; - -const config = compose(orgMainConfigMain, { - datastreamId: "BOGUS", -}); - -createFixture({ - title: - "C13819: Sending invalid config ID rejects command promise with useful error", -}); - -test.meta({ - ID: "C13819", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -const sendEvent = ClientFunction(() => { - return window.alloy("sendEvent").catch((e) => e.message); -}); - -test("Test C13819: Sending invalid config ID rejects command promise with useful error", async (t) => { - await configureAlloyInstance("alloy", config); - const errorMessage = await sendEvent(); - await t - .expect(errorMessage) - .contains("The server responded with a status code 400 and response body"); - await t.expect(errorMessage).contains("EXEG-0003-400"); -}); diff --git a/packages/core/test/functional/specs/Command Logic/C2580.js b/packages/core/test/functional/specs/Command Logic/C2580.js deleted file mode 100644 index 37923ffbe..000000000 --- a/packages/core/test/functional/specs/Command Logic/C2580.js +++ /dev/null @@ -1,48 +0,0 @@ -/* -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 { injectAlloyDuringTest } from "../../helpers/createFixture/clientScripts.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; - -const debugEnabledConfig = compose(orgMainConfigMain, debugEnabled); - -createFixture({ - title: "C2580: Command queueing test", - includeAlloyLibrary: false, -}); - -test.meta({ - ID: "C2580", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -const getAlloyCommandQueueLength = ClientFunction(() => { - return window.alloy.q.length; -}); - -test("C2580: Command queueing test.", async () => { - const alloy = createAlloyProxy(); - await alloy.configureAsync(debugEnabledConfig); - await alloy.getLibraryInfoAsync(); - await t.expect(getAlloyCommandQueueLength()).eql(2); - const logger = await createConsoleLogger(); - await injectAlloyDuringTest(); - await logger.info.expectMessageMatching(/Executing getLibraryInfo command/); -}); diff --git a/packages/core/test/functional/specs/Command Logic/C2585.js b/packages/core/test/functional/specs/Command Logic/C2585.js deleted file mode 100644 index 8ac8f61cd..000000000 --- a/packages/core/test/functional/specs/Command Logic/C2585.js +++ /dev/null @@ -1,35 +0,0 @@ -/* -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 createAlloyProxy from "../../helpers/createAlloyProxy.js"; -import createFixture from "../../helpers/createFixture/index.js"; - -createFixture({ - title: - "C2585: Throws error when configure is not the first command executed.", -}); - -test.meta({ - ID: "C2585", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -test("Test C2585: Throw error when configure is not the first command executed.", async (t) => { - // Note: unable to enable logging with url parameter or enabler logger config. - const alloy = createAlloyProxy(); - const sendEventErrorMessage = await alloy.sendEventErrorMessage(); - await t - .expect(sendEventErrorMessage) - .match( - /The library must be configured first. Please do so by executing the configure command./, - ); -}); diff --git a/packages/core/test/functional/specs/Command Logic/C2587.js b/packages/core/test/functional/specs/Command Logic/C2587.js deleted file mode 100644 index c36daa7d6..000000000 --- a/packages/core/test/functional/specs/Command Logic/C2587.js +++ /dev/null @@ -1,48 +0,0 @@ -/* -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 { ClientFunction } from "testcafe"; -import createFixture from "../../helpers/createFixture/index.js"; -import { - compose, - orgMainConfigMain, - debugEnabled, -} from "../../helpers/constants/configParts/index.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; - -const config = compose(orgMainConfigMain, debugEnabled); - -createFixture({ - title: "C2587: Throw error when executing command that doesn't exist.", -}); - -test.meta({ - ID: "C2587", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -const bogusCommand = ClientFunction(() => { - return window.alloy("bogusCommand").then( - () => {}, - (error) => error.message, - ); -}); - -test("Test C2587: Throw error when executing command that doesn't exist", async (t) => { - const alloy = createAlloyProxy(); - await alloy.configure(config); - - const errorMessage = await bogusCommand(); - await t - .expect(errorMessage) - .match(/The bogusCommand command does not exist./); -}); diff --git a/packages/core/test/functional/specs/Command Logic/C2588.js b/packages/core/test/functional/specs/Command Logic/C2588.js deleted file mode 100644 index b812ed4eb..000000000 --- a/packages/core/test/functional/specs/Command Logic/C2588.js +++ /dev/null @@ -1,36 +0,0 @@ -/* -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 createFixture from "../../helpers/createFixture/index.js"; -import { orgMainConfigMain } from "../../helpers/constants/configParts/index.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; - -createFixture({ - title: "C2588: Throws error when configure is executed multiple times.", -}); - -test.meta({ - ID: "C2588", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -test("Test C2588: Throw error when configure is executed multiple times.", async (t) => { - const alloy = createAlloyProxy(); - await alloy.configure(orgMainConfigMain); - const errorMessage = await alloy.configureErrorMessage(orgMainConfigMain); - - await t - .expect(errorMessage) - .match( - /The library has already been configured and may only be configured once./, - ); -}); diff --git a/packages/core/test/functional/specs/Command Logic/C3484892.js b/packages/core/test/functional/specs/Command Logic/C3484892.js deleted file mode 100644 index 46c60f9dc..000000000 --- a/packages/core/test/functional/specs/Command Logic/C3484892.js +++ /dev/null @@ -1,33 +0,0 @@ -/* -Copyright 2021 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 createFixture from "../../helpers/createFixture/index.js"; -import { orgMainConfigMain } from "../../helpers/constants/configParts/index.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; - -const title = - "C3484892: Resolves promise with empty result object from configure command."; - -createFixture({ - title, -}); - -test.meta({ - ID: "C3484892", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -test(title, async (t) => { - const alloy = createAlloyProxy(); - const result = await alloy.configure(orgMainConfigMain); - await t.expect(result).eql({}); -}); diff --git a/packages/core/test/functional/specs/Config Overrides/C7437530.js b/packages/core/test/functional/specs/Config Overrides/C7437530.js deleted file mode 100644 index ae89bae74..000000000 --- a/packages/core/test/functional/specs/Config Overrides/C7437530.js +++ /dev/null @@ -1,239 +0,0 @@ -/* -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 } from "testcafe"; -import createNetworkLogger from "../../helpers/networkLogger/index.js"; -import { responseStatus } from "../../helpers/assertions/index.js"; -import createFixture from "../../helpers/createFixture/index.js"; -import { - compose, - configOverridesMain as overrides, - configOverridesAlt as alternateOverrides, - orgMainConfigMain, - debugEnabled, -} from "../../helpers/constants/configParts/index.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; - -const networkLogger = createNetworkLogger(); -const config = compose(orgMainConfigMain, debugEnabled); - -createFixture({ - title: - "C7437530: sendEvent can receive config overrides in command options and in configure", - requestHooks: [networkLogger.edgeEndpointLogs], -}); - -test.meta({ - ID: "C2592", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -test("Test C7437530: `sendEvent` can receive config overrides in command options", async () => { - const alloy = createAlloyProxy(); - await alloy.configure(config); - await alloy.sendEvent({ - edgeConfigOverrides: overrides, - }); - - await responseStatus(networkLogger.edgeEndpointLogs.requests, [200, 207]); - - await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(1); - - const request = JSON.parse( - networkLogger.edgeEndpointLogs.requests[0].request.body, - ); - - await t - .expect(request.events[0].xdm.implementationDetails.name) - .eql("https://ns.adobe.com/experience/alloy"); - await t - .expect( - request.meta.configOverrides.com_adobe_experience_platform.datasets.event, - ) - .eql(overrides.com_adobe_experience_platform.datasets.event); - await t - .expect(request.meta.configOverrides.com_adobe_analytics.reportSuites) - .eql(overrides.com_adobe_analytics.reportSuites); - await t - .expect(request.meta.configOverrides.com_adobe_identity.idSyncContainerId) - .eql(overrides.com_adobe_identity.idSyncContainerId); - await t - .expect(request.meta.configOverrides.com_adobe_target.propertyToken) - .eql(overrides.com_adobe_target.propertyToken); - await t.expect(request.meta.state.cookiesEnabled).eql(true); - await t.expect(request.meta.state.domain).ok(); -}); - -test("Test C7437530: `sendEvent` doesn't contain empty configOverrides if edgeConfigOverrides are not in options", async () => { - const alloy = createAlloyProxy(); - await alloy.configure(config); - await alloy.sendEvent({}); - - await responseStatus(networkLogger.edgeEndpointLogs.requests, [200, 207]); - - await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(1); - - const request = JSON.parse( - networkLogger.edgeEndpointLogs.requests[0].request.body, - ); - - await t - .expect(request.events[0].xdm.implementationDetails.name) - .eql("https://ns.adobe.com/experience/alloy"); - await t.expect(request.meta.configOverrides).eql(undefined); -}); - -test("Test C7437530: `sendEvent` can receive config overrides from configure", async () => { - const alloy = createAlloyProxy(); - await alloy.configure( - compose(config, { - edgeConfigOverrides: overrides, - }), - ); - await alloy.sendEvent({}); - - await responseStatus(networkLogger.edgeEndpointLogs.requests, [200, 207]); - - await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(1); - - const request = JSON.parse( - networkLogger.edgeEndpointLogs.requests[0].request.body, - ); - - await t - .expect(request.events[0].xdm.implementationDetails.name) - .eql("https://ns.adobe.com/experience/alloy"); - await t - .expect( - request.meta.configOverrides.com_adobe_experience_platform.datasets.event, - ) - .eql(overrides.com_adobe_experience_platform.datasets.event); - await t - .expect(request.meta.configOverrides.com_adobe_analytics.reportSuites) - .eql(overrides.com_adobe_analytics.reportSuites); - await t - .expect(request.meta.configOverrides.com_adobe_identity.idSyncContainerId) - .eql(overrides.com_adobe_identity.idSyncContainerId); - await t - .expect(request.meta.configOverrides.com_adobe_target.propertyToken) - .eql(overrides.com_adobe_target.propertyToken); - await t.expect(request.meta.state.cookiesEnabled).eql(true); - await t.expect(request.meta.state.domain).ok(); -}); - -test("Test C7437530: overrides from `sendEvent` should take precedence over the ones from `configure`", async () => { - const alloy = createAlloyProxy(); - await alloy.configure( - compose(config, { - edgeConfigOverrides: alternateOverrides, - }), - ); - await alloy.sendEvent({ - edgeConfigOverrides: overrides, - }); - - await responseStatus(networkLogger.edgeEndpointLogs.requests, [200, 207]); - - await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(1); - - const request = JSON.parse( - networkLogger.edgeEndpointLogs.requests[0].request.body, - ); - - await t - .expect(request.events[0].xdm.implementationDetails.name) - .eql("https://ns.adobe.com/experience/alloy"); - await t - .expect( - request.meta.configOverrides.com_adobe_experience_platform.datasets.event, - ) - .eql(overrides.com_adobe_experience_platform.datasets.event); - await t - .expect(request.meta.configOverrides.com_adobe_analytics.reportSuites) - .eql(overrides.com_adobe_analytics.reportSuites); - await t - .expect(request.meta.configOverrides.com_adobe_identity.idSyncContainerId) - .eql(overrides.com_adobe_identity.idSyncContainerId); - await t - .expect(request.meta.configOverrides.com_adobe_target.propertyToken) - .eql(overrides.com_adobe_target.propertyToken); - await t.expect(request.meta.state.cookiesEnabled).eql(true); - await t.expect(request.meta.state.domain).ok(); -}); - -test("Test C7437530: empty configuration overrides should not be sent to the Edge", async () => { - const alloy = createAlloyProxy(); - await alloy.configure( - compose(config, { - edgeConfigOverrides: compose(alternateOverrides, { - com_adobe_target: { - propertyToken: "", - }, - }), - }), - ); - await alloy.sendEvent({ - edgeConfigOverrides: compose(overrides, { - com_adobe_target: { - propertyToken: "", - }, - }), - }); - - await responseStatus(networkLogger.edgeEndpointLogs.requests, [200, 207]); - - await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(1); - - const request = JSON.parse( - networkLogger.edgeEndpointLogs.requests[0].request.body, - ); - - await t - .expect(request.events[0].xdm.implementationDetails.name) - .eql("https://ns.adobe.com/experience/alloy"); - await t - .expect( - request.meta.configOverrides.com_adobe_experience_platform.datasets.event, - ) - .eql(overrides.com_adobe_experience_platform.datasets.event); - await t - .expect(request.meta.configOverrides.com_adobe_analytics.reportSuites) - .eql(overrides.com_adobe_analytics.reportSuites); - await t - .expect(request.meta.configOverrides.com_adobe_identity.idSyncContainerId) - .eql(overrides.com_adobe_identity.idSyncContainerId); - await t.expect(request.meta.configOverrides.com_adobe_target).eql(undefined); - await t.expect(request.meta.state.cookiesEnabled).eql(true); - await t.expect(request.meta.state.domain).ok(); -}); - -test("Test C7437530: `sendEvent` can override the datastreamId", async () => { - const alloy = createAlloyProxy(); - await alloy.configure(config); - const { datastreamId: originalDatastreamId } = config; - const alternateDatastreamId = `${originalDatastreamId}:dev`; - await alloy.sendEvent({ - edgeConfigOverrides: { - datastreamId: alternateDatastreamId, - }, - }); - - await responseStatus(networkLogger.edgeEndpointLogs.requests, [200, 207]); - await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(1); - const [request] = networkLogger.edgeEndpointLogs.requests; - await t.expect(request.request.url).contains(alternateDatastreamId); - - const body = JSON.parse(request.request.body); - await t - .expect(body.meta.sdkConfig.datastream.original) - .eql(originalDatastreamId); -}); diff --git a/packages/core/test/functional/specs/Config Overrides/C7437531.js b/packages/core/test/functional/specs/Config Overrides/C7437531.js deleted file mode 100644 index e5136b16e..000000000 --- a/packages/core/test/functional/specs/Config Overrides/C7437531.js +++ /dev/null @@ -1,184 +0,0 @@ -/* -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 } from "testcafe"; -import createNetworkLogger from "../../helpers/networkLogger/index.js"; -import { responseStatus } from "../../helpers/assertions/index.js"; -import createFixture from "../../helpers/createFixture/index.js"; -import { - compose, - configOverridesMain as overrides, - configOverridesAlt as alternateOverrides, - orgMainConfigMain, - debugEnabled, -} from "../../helpers/constants/configParts/index.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; - -const networkLogger = createNetworkLogger(); -const config = compose(orgMainConfigMain, debugEnabled); - -createFixture({ - title: - "C7437531: `getIdentity` can receive config overrides in command options and in `configure`", - requestHooks: [networkLogger.acquireEndpointLogs], -}); - -test.meta({ - ID: "C2592", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -test("Test C7437531: `getIdentity` can receive config overrides in command options", async () => { - const alloy = createAlloyProxy(); - await alloy.configure(config); - // this should get an ECID - await alloy.getIdentity({ - edgeConfigOverrides: overrides, - }); - - await responseStatus(networkLogger.acquireEndpointLogs.requests, [200, 207]); - await t.expect(networkLogger.acquireEndpointLogs.requests.length).eql(1); - - const request = JSON.parse( - networkLogger.acquireEndpointLogs.requests[0].request.body, - ); - - await t - .expect( - request.meta.configOverrides.com_adobe_experience_platform.datasets.event, - ) - .eql(overrides.com_adobe_experience_platform.datasets.event); - await t - .expect(request.meta.configOverrides.com_adobe_analytics.reportSuites) - .eql(overrides.com_adobe_analytics.reportSuites); - await t - .expect(request.meta.configOverrides.com_adobe_identity.idSyncContainerId) - .eql(overrides.com_adobe_identity.idSyncContainerId); - await t - .expect(request.meta.configOverrides.com_adobe_target.propertyToken) - .eql(overrides.com_adobe_target.propertyToken); -}); - -test("Test C7437531: `getIdentity` can receive config overrides from `configure`", async () => { - const alloy = createAlloyProxy(); - await alloy.configure(compose(config, { edgeConfigOverrides: overrides })); - // this should get an ECID - await alloy.getIdentity(); - - await responseStatus(networkLogger.acquireEndpointLogs.requests, [200, 207]); - await t.expect(networkLogger.acquireEndpointLogs.requests.length).eql(1); - - const request = JSON.parse( - networkLogger.acquireEndpointLogs.requests[0].request.body, - ); - - await t - .expect( - request.meta.configOverrides.com_adobe_experience_platform.datasets.event, - ) - .eql(overrides.com_adobe_experience_platform.datasets.event); - await t - .expect(request.meta.configOverrides.com_adobe_analytics.reportSuites) - .eql(overrides.com_adobe_analytics.reportSuites); - await t - .expect(request.meta.configOverrides.com_adobe_identity.idSyncContainerId) - .eql(overrides.com_adobe_identity.idSyncContainerId); - await t - .expect(request.meta.configOverrides.com_adobe_target.propertyToken) - .eql(overrides.com_adobe_target.propertyToken); -}); - -test("Test C7437531: overrides from `getIdentity` should take precedence over the ones from `configure`", async () => { - const alloy = createAlloyProxy(); - await alloy.configure( - compose(config, { edgeConfigOverrides: alternateOverrides }), - ); - // this should get an ECID - await alloy.getIdentity({ edgeConfigOverrides: overrides }); - - await responseStatus(networkLogger.acquireEndpointLogs.requests, [200, 207]); - await t.expect(networkLogger.acquireEndpointLogs.requests.length).eql(1); - - const request = JSON.parse( - networkLogger.acquireEndpointLogs.requests[0].request.body, - ); - - await t - .expect( - request.meta.configOverrides.com_adobe_experience_platform.datasets.event, - ) - .eql(overrides.com_adobe_experience_platform.datasets.event); - await t - .expect(request.meta.configOverrides.com_adobe_analytics.reportSuites) - .eql(overrides.com_adobe_analytics.reportSuites); - await t - .expect(request.meta.configOverrides.com_adobe_identity.idSyncContainerId) - .eql(overrides.com_adobe_identity.idSyncContainerId); - await t - .expect(request.meta.configOverrides.com_adobe_target.propertyToken) - .eql(overrides.com_adobe_target.propertyToken); -}); - -test("Test C7437531: empty configuration overrides should not be sent to the Edge", async () => { - const alloy = createAlloyProxy(); - await alloy.configure(config); - // this should get an ECID - await alloy.getIdentity({ - edgeConfigOverrides: compose(overrides, { - com_adobe_target: { - propertyToken: "", - }, - }), - }); - - await responseStatus(networkLogger.acquireEndpointLogs.requests, [200, 207]); - await t.expect(networkLogger.acquireEndpointLogs.requests.length).eql(1); - - const request = JSON.parse( - networkLogger.acquireEndpointLogs.requests[0].request.body, - ); - - await t - .expect( - request.meta.configOverrides.com_adobe_experience_platform.datasets.event, - ) - .eql(overrides.com_adobe_experience_platform.datasets.event); - await t - .expect(request.meta.configOverrides.com_adobe_analytics.reportSuites) - .eql(overrides.com_adobe_analytics.reportSuites); - await t - .expect(request.meta.configOverrides.com_adobe_identity.idSyncContainerId) - .eql(overrides.com_adobe_identity.idSyncContainerId); - await t.expect(request.meta.configOverrides.com_adobe_target).eql(undefined); -}); - -test("Test C7437531: `getIdentity` can override the datastreamId", async () => { - const alloy = createAlloyProxy(); - await alloy.configure(config); - const { datastreamId: originalDatastreamId } = config; - const alternateDatastreamId = `${originalDatastreamId}:dev`; - await alloy.getIdentity({ - edgeConfigOverrides: { - datastreamId: alternateDatastreamId, - }, - }); - - await responseStatus(networkLogger.acquireEndpointLogs.requests, [200, 207]); - await t.expect(networkLogger.acquireEndpointLogs.requests.length).eql(1); - const [request] = networkLogger.acquireEndpointLogs.requests; - await t.expect(request.request.url).contains(alternateDatastreamId); - - const body = JSON.parse(request.request.body); - await t - .expect(body.meta.sdkConfig.datastream.original) - .eql(originalDatastreamId); -}); diff --git a/packages/core/test/functional/specs/Config Overrides/C7437532.js b/packages/core/test/functional/specs/Config Overrides/C7437532.js deleted file mode 100644 index 643975afc..000000000 --- a/packages/core/test/functional/specs/Config Overrides/C7437532.js +++ /dev/null @@ -1,192 +0,0 @@ -/* -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 } from "testcafe"; -import createNetworkLogger from "../../helpers/networkLogger/index.js"; -import { responseStatus } from "../../helpers/assertions/index.js"; -import createFixture from "../../helpers/createFixture/index.js"; -import { - compose, - configOverridesMain as overrides, - configOverridesAlt as alternateOverrides, - orgMainConfigMain, - debugEnabled, - consentIn, -} from "../../helpers/constants/configParts/index.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; - -const networkLogger = createNetworkLogger(); -const config = compose(orgMainConfigMain, consentIn, debugEnabled); - -createFixture({ - title: - "C7437532: `appendIdentityToUrl` can receive config overrides in command options and in `configure`", - requestHooks: [networkLogger.acquireEndpointLogs], -}); - -test.meta({ - ID: "C2592", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -test("Test C7437532: `appendIdentityToUrl` can receive config overrides in command options", async () => { - const alloy = createAlloyProxy(); - await alloy.configure(config); - // this should get an ECID - await alloy.appendIdentityToUrl({ - url: "https://example.com", - edgeConfigOverrides: overrides, - }); - - await responseStatus(networkLogger.acquireEndpointLogs.requests, [200, 207]); - await t.expect(networkLogger.acquireEndpointLogs.requests.length).eql(1); - - const request = JSON.parse( - networkLogger.acquireEndpointLogs.requests[0].request.body, - ); - - await t - .expect( - request.meta.configOverrides.com_adobe_experience_platform.datasets.event, - ) - .eql(overrides.com_adobe_experience_platform.datasets.event); - await t - .expect(request.meta.configOverrides.com_adobe_analytics.reportSuites) - .eql(overrides.com_adobe_analytics.reportSuites); - await t - .expect(request.meta.configOverrides.com_adobe_identity.idSyncContainerId) - .eql(overrides.com_adobe_identity.idSyncContainerId); - await t - .expect(request.meta.configOverrides.com_adobe_target.propertyToken) - .eql(overrides.com_adobe_target.propertyToken); -}); - -test("Test C7437532: `appendIdentityToUrl` can receive config overrides from `configure`", async () => { - const alloy = createAlloyProxy(); - await alloy.configure(compose(config, { edgeConfigOverrides: overrides })); - // this should get an ECID - await alloy.appendIdentityToUrl({ - url: "https://example.com", - }); - - await responseStatus(networkLogger.acquireEndpointLogs.requests, [200, 207]); - await t.expect(networkLogger.acquireEndpointLogs.requests.length).eql(1); - - const request = JSON.parse( - networkLogger.acquireEndpointLogs.requests[0].request.body, - ); - - await t - .expect( - request.meta.configOverrides.com_adobe_experience_platform.datasets.event, - ) - .eql(overrides.com_adobe_experience_platform.datasets.event); - await t - .expect(request.meta.configOverrides.com_adobe_analytics.reportSuites) - .eql(overrides.com_adobe_analytics.reportSuites); - await t - .expect(request.meta.configOverrides.com_adobe_identity.idSyncContainerId) - .eql(overrides.com_adobe_identity.idSyncContainerId); - await t - .expect(request.meta.configOverrides.com_adobe_target.propertyToken) - .eql(overrides.com_adobe_target.propertyToken); -}); - -test("Test C7437532: overrides from the `appendIdentityToUrl` should take precedence over the ones from `configure`", async () => { - const alloy = createAlloyProxy(); - await alloy.configure( - compose(config, { edgeConfigOverrides: alternateOverrides }), - ); - // this should get an ECID - await alloy.appendIdentityToUrl({ - url: "https://example.com", - edgeConfigOverrides: overrides, - }); - - await responseStatus(networkLogger.acquireEndpointLogs.requests, [200, 207]); - await t.expect(networkLogger.acquireEndpointLogs.requests.length).eql(1); - - const request = JSON.parse( - networkLogger.acquireEndpointLogs.requests[0].request.body, - ); - - await t - .expect( - request.meta.configOverrides.com_adobe_experience_platform.datasets.event, - ) - .eql(overrides.com_adobe_experience_platform.datasets.event); - await t - .expect(request.meta.configOverrides.com_adobe_analytics.reportSuites) - .eql(overrides.com_adobe_analytics.reportSuites); - await t - .expect(request.meta.configOverrides.com_adobe_identity.idSyncContainerId) - .eql(overrides.com_adobe_identity.idSyncContainerId); - await t - .expect(request.meta.configOverrides.com_adobe_target.propertyToken) - .eql(overrides.com_adobe_target.propertyToken); -}); - -test("Test C7437532: empty configuration overrides should not be sent to the Edge", async () => { - const alloy = createAlloyProxy(); - await alloy.configure(config); - // this should get an ECID - await alloy.appendIdentityToUrl({ - url: "https://example.com", - edgeConfigOverrides: compose(overrides, { - com_adobe_target: { - propertyToken: "", - }, - }), - }); - - await responseStatus(networkLogger.acquireEndpointLogs.requests, [200, 207]); - await t.expect(networkLogger.acquireEndpointLogs.requests.length).eql(1); - - const request = JSON.parse( - networkLogger.acquireEndpointLogs.requests[0].request.body, - ); - - await t - .expect( - request.meta.configOverrides.com_adobe_experience_platform.datasets.event, - ) - .eql(overrides.com_adobe_experience_platform.datasets.event); - await t - .expect(request.meta.configOverrides.com_adobe_analytics.reportSuites) - .eql(overrides.com_adobe_analytics.reportSuites); - await t - .expect(request.meta.configOverrides.com_adobe_identity.idSyncContainerId) - .eql(overrides.com_adobe_identity.idSyncContainerId); - await t.expect(request.meta.configOverrides.com_adobe_target).eql(undefined); -}); - -test("Test C7437532: `appendIdentityToUrl` can override the datastreamId", async () => { - const alloy = createAlloyProxy(); - await alloy.configure(config); - const { datastreamId: originalDatastreamId } = config; - const alternateDatastreamId = `${originalDatastreamId}:dev`; - await alloy.appendIdentityToUrl({ - url: "https://example.com", - edgeConfigOverrides: { - datastreamId: alternateDatastreamId, - }, - }); - - await responseStatus(networkLogger.acquireEndpointLogs.requests, [200, 207]); - await t.expect(networkLogger.acquireEndpointLogs.requests.length).eql(1); - const [request] = networkLogger.acquireEndpointLogs.requests; - await t.expect(request.request.url).contains(alternateDatastreamId); - const body = JSON.parse(request.request.body); - await t - .expect(body.meta.sdkConfig.datastream.original) - .eql(originalDatastreamId); -}); diff --git a/packages/core/test/functional/specs/Config Overrides/C7437533.js b/packages/core/test/functional/specs/Config Overrides/C7437533.js deleted file mode 100644 index 812990e25..000000000 --- a/packages/core/test/functional/specs/Config Overrides/C7437533.js +++ /dev/null @@ -1,200 +0,0 @@ -/* -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 } from "testcafe"; -import createNetworkLogger from "../../helpers/networkLogger/index.js"; -import { responseStatus } from "../../helpers/assertions/index.js"; -import createFixture from "../../helpers/createFixture/index.js"; -import { - compose, - configOverridesMain as overrides, - configOverridesAlt as alternateOverrides, - orgMainConfigMain, - debugEnabled, -} from "../../helpers/constants/configParts/index.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; -import { IAB_CONSENT_IN } from "../../helpers/constants/consent.js"; - -const networkLogger = createNetworkLogger(); -const config = compose(orgMainConfigMain, debugEnabled); - -createFixture({ - title: - "C7437533: `setConsent` can receive config overrides in command options and in `configure`", - requestHooks: [networkLogger.setConsentEndpointLogs], -}); - -test.meta({ - ID: "C2592", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -test("Test C7437533: `setConsent` can receive config overrides in command options", async () => { - const alloy = createAlloyProxy(); - await alloy.configure(config); - await alloy.setConsent( - compose(IAB_CONSENT_IN, { edgeConfigOverrides: overrides }), - ); - - await responseStatus( - networkLogger.setConsentEndpointLogs.requests, - [200, 207], - ); - await t.expect(networkLogger.setConsentEndpointLogs.requests.length).eql(1); - - const request = JSON.parse( - networkLogger.setConsentEndpointLogs.requests[0].request.body, - ); - - await t - .expect( - request.meta.configOverrides.com_adobe_experience_platform.datasets.event, - ) - .eql(overrides.com_adobe_experience_platform.datasets.event); - await t - .expect(request.meta.configOverrides.com_adobe_analytics.reportSuites) - .eql(overrides.com_adobe_analytics.reportSuites); - await t - .expect(request.meta.configOverrides.com_adobe_identity.idSyncContainerId) - .eql(overrides.com_adobe_identity.idSyncContainerId); - await t - .expect(request.meta.configOverrides.com_adobe_target.propertyToken) - .eql(overrides.com_adobe_target.propertyToken); -}); - -test("Test C7437533: `setConsent` can receive config overrides from `configure`", async () => { - const alloy = createAlloyProxy(); - await alloy.configure(compose(config, { edgeConfigOverrides: overrides })); - await alloy.setConsent(IAB_CONSENT_IN); - - await responseStatus( - networkLogger.setConsentEndpointLogs.requests, - [200, 207], - ); - await t.expect(networkLogger.setConsentEndpointLogs.requests.length).eql(1); - - const request = JSON.parse( - networkLogger.setConsentEndpointLogs.requests[0].request.body, - ); - - await t - .expect( - request.meta.configOverrides.com_adobe_experience_platform.datasets.event, - ) - .eql(overrides.com_adobe_experience_platform.datasets.event); - await t - .expect(request.meta.configOverrides.com_adobe_analytics.reportSuites) - .eql(overrides.com_adobe_analytics.reportSuites); - await t - .expect(request.meta.configOverrides.com_adobe_identity.idSyncContainerId) - .eql(overrides.com_adobe_identity.idSyncContainerId); - await t - .expect(request.meta.configOverrides.com_adobe_target.propertyToken) - .eql(overrides.com_adobe_target.propertyToken); -}); - -test("Test C7437533: overrides from `setConsent` should take precedence over the ones from `configure`", async () => { - const alloy = createAlloyProxy(); - await alloy.configure(compose(config, { edgeConfigOverrides: overrides })); - await alloy.setConsent(IAB_CONSENT_IN, { - edgeConfigOverrides: alternateOverrides, - }); - - await responseStatus( - networkLogger.setConsentEndpointLogs.requests, - [200, 207], - ); - await t.expect(networkLogger.setConsentEndpointLogs.requests.length).eql(1); - - const request = JSON.parse( - networkLogger.setConsentEndpointLogs.requests[0].request.body, - ); - - await t - .expect( - request.meta.configOverrides.com_adobe_experience_platform.datasets.event, - ) - .eql(overrides.com_adobe_experience_platform.datasets.event); - await t - .expect(request.meta.configOverrides.com_adobe_analytics.reportSuites) - .eql(overrides.com_adobe_analytics.reportSuites); - await t - .expect(request.meta.configOverrides.com_adobe_identity.idSyncContainerId) - .eql(overrides.com_adobe_identity.idSyncContainerId); - await t - .expect(request.meta.configOverrides.com_adobe_target.propertyToken) - .eql(overrides.com_adobe_target.propertyToken); -}); - -test("Test C7437533: empty configuration overrides should not be sent to the Edge", async () => { - const alloy = createAlloyProxy(); - await alloy.configure(config); - await alloy.setConsent( - compose(IAB_CONSENT_IN, { - edgeConfigOverrides: compose(overrides, { - com_adobe_target: { - propertyToken: "", - }, - }), - }), - ); - - await responseStatus( - networkLogger.setConsentEndpointLogs.requests, - [200, 207], - ); - await t.expect(networkLogger.setConsentEndpointLogs.requests.length).eql(1); - - const request = JSON.parse( - networkLogger.setConsentEndpointLogs.requests[0].request.body, - ); - - await t - .expect( - request.meta.configOverrides.com_adobe_experience_platform.datasets.event, - ) - .eql(overrides.com_adobe_experience_platform.datasets.event); - await t - .expect(request.meta.configOverrides.com_adobe_analytics.reportSuites) - .eql(overrides.com_adobe_analytics.reportSuites); - await t - .expect(request.meta.configOverrides.com_adobe_identity.idSyncContainerId) - .eql(overrides.com_adobe_identity.idSyncContainerId); - await t.expect(request.meta.configOverrides.com_adobe_target).eql(undefined); -}); - -test("Test C7437533: `setConsent` can override the datastreamId", async () => { - const alloy = createAlloyProxy(); - await alloy.configure(config); - const { datastreamId: originalDatastreamId } = config; - const alternateDatastreamId = `${originalDatastreamId}:dev`; - await alloy.setConsent( - compose(IAB_CONSENT_IN, { - edgeConfigOverrides: { - datastreamId: alternateDatastreamId, - }, - }), - ); - - await responseStatus( - networkLogger.setConsentEndpointLogs.requests, - [200, 207], - ); - await t.expect(networkLogger.setConsentEndpointLogs.requests.length).eql(1); - const [request] = networkLogger.setConsentEndpointLogs.requests; - await t.expect(request.request.url).contains(alternateDatastreamId); - - const body = JSON.parse(request.request.body); - await t - .expect(body.meta.sdkConfig.datastream.original) - .eql(originalDatastreamId); -}); diff --git a/packages/core/test/functional/specs/Consent/C14404.js b/packages/core/test/functional/specs/Consent/C14404.js deleted file mode 100644 index 7b04a0725..000000000 --- a/packages/core/test/functional/specs/Consent/C14404.js +++ /dev/null @@ -1,64 +0,0 @@ -/* -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 } from "testcafe"; -import createFixture from "../../helpers/createFixture/index.js"; -import createNetworkLogger from "../../helpers/networkLogger/index.js"; - -import { - compose, - orgMainConfigMain, - consentPending, - debugEnabled, -} from "../../helpers/constants/configParts/index.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; -import { CONSENT_OUT, CONSENT_IN } from "../../helpers/constants/consent.js"; -import cookies from "../../helpers/cookies.js"; -import { MAIN_CONSENT_COOKIE_NAME } from "../../helpers/constants/cookies.js"; - -const config = compose(orgMainConfigMain, consentPending, debugEnabled); - -const networkLogger = createNetworkLogger(); - -createFixture({ - title: - "C14404: User cannot consent to all purposes after consenting to no purposes", - requestHooks: [ - networkLogger.edgeEndpointLogs, - networkLogger.setConsentEndpointLogs, - ], -}); - -test.meta({ - ID: "C14404", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -test("Test C14404: User can consent to all purposes after consenting to no purposes", async () => { - const alloy = createAlloyProxy(); - await alloy.configure(config); - await alloy.setConsent(CONSENT_OUT); - - // set consent back to in for the same user - await alloy.setConsent(CONSENT_IN); - - await t.expect(networkLogger.setConsentEndpointLogs.requests.length).eql(2); - - const consentCookieValue = await cookies.get(MAIN_CONSENT_COOKIE_NAME); - - await t.expect(consentCookieValue).ok("No consent cookie found."); - await t.expect(consentCookieValue).eql("general=in"); - - // make sure event goes out - await alloy.sendEvent(); - await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(1); -}); diff --git a/packages/core/test/functional/specs/Consent/C14405.js b/packages/core/test/functional/specs/Consent/C14405.js deleted file mode 100644 index d9bfc3113..000000000 --- a/packages/core/test/functional/specs/Consent/C14405.js +++ /dev/null @@ -1,50 +0,0 @@ -/* -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 createFixture from "../../helpers/createFixture/index.js"; -import createNetworkLogger from "../../helpers/networkLogger/index.js"; - -import { - compose, - orgMainConfigMain, - consentPending, - debugEnabled, -} from "../../helpers/constants/configParts/index.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; - -import { CONSENT_IN } from "../../helpers/constants/consent.js"; - -const config = compose(orgMainConfigMain, consentPending, debugEnabled); - -const networkLogger = createNetworkLogger(); - -createFixture({ - title: "C14405: Unidentified user can consent to all purposes", - requestHooks: [networkLogger.edgeEndpointLogs], -}); - -test.meta({ - ID: "C14405", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -test("Test C14405: Unidentified user can consent to all purposes", async (t) => { - const alloy = createAlloyProxy(); - await alloy.configure(config); - await alloy.setConsent(CONSENT_IN); - await alloy.sendEvent(); - await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(1); - const request = networkLogger.edgeEndpointLogs.requests[0].request.body; - await t - .expect(request) - .contains('"name":"https://ns.adobe.com/experience/alloy"'); -}); diff --git a/packages/core/test/functional/specs/Consent/C14406.js b/packages/core/test/functional/specs/Consent/C14406.js deleted file mode 100644 index 83f75f1ba..000000000 --- a/packages/core/test/functional/specs/Consent/C14406.js +++ /dev/null @@ -1,48 +0,0 @@ -/* -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 createFixture from "../../helpers/createFixture/index.js"; -import createNetworkLogger from "../../helpers/networkLogger/index.js"; -import { - compose, - orgMainConfigMain, - consentPending, - debugEnabled, -} from "../../helpers/constants/configParts/index.js"; -import createConsoleLogger from "../../helpers/consoleLogger/index.js"; - -import { CONSENT_OUT } from "../../helpers/constants/consent.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; - -const config = compose(orgMainConfigMain, consentPending, debugEnabled); - -const networkLogger = createNetworkLogger(); - -createFixture({ - title: "C14406: Unidentified user can consent to no purposes", - requestHooks: [networkLogger.edgeEndpointLogs], -}); - -test.meta({ - ID: "C14406", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -test("Test C14406: Unidentified user can consent to no purposes", async (t) => { - const logger = await createConsoleLogger(); - const alloy = createAlloyProxy(); - await alloy.configure(config); - await alloy.setConsent(CONSENT_OUT); - await alloy.sendEvent(); - await logger.warn.expectMessageMatching(/user declined consent/); - await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(0); -}); diff --git a/packages/core/test/functional/specs/Consent/C14407.js b/packages/core/test/functional/specs/Consent/C14407.js deleted file mode 100644 index 4cf8d589b..000000000 --- a/packages/core/test/functional/specs/Consent/C14407.js +++ /dev/null @@ -1,48 +0,0 @@ -/* -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 } from "testcafe"; -import createNetworkLogger from "../../helpers/networkLogger/index.js"; -import createFixture from "../../helpers/createFixture/index.js"; -import { CONSENT_IN } from "../../helpers/constants/consent.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; -import reloadPage from "../../helpers/reloadPage.js"; - -const networkLogger = createNetworkLogger(); - -createFixture({ - title: "C14407 - Consenting to all purposes should be persisted.", - requestHooks: [networkLogger.edgeEndpointLogs], -}); - -test.meta({ - ID: "C14407", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -const config = { - datastreamId: "9999999", - orgId: "53A16ACB5CC1D3760A495C99@AdobeOrg", - defaultConsent: "pending", - idMigrationEnabled: false, - debugEnabled: true, -}; - -test("C14407 - Consenting to all purposes should be persisted.", async () => { - const alloy = createAlloyProxy(); - await alloy.configure(config); - await alloy.setConsent(CONSENT_IN); - await reloadPage(); - await alloy.configure(config); - await alloy.sendEvent(); - await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(1); -}); diff --git a/packages/core/test/functional/specs/Consent/C14409.js b/packages/core/test/functional/specs/Consent/C14409.js deleted file mode 100644 index e38051944..000000000 --- a/packages/core/test/functional/specs/Consent/C14409.js +++ /dev/null @@ -1,55 +0,0 @@ -/* -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 } from "testcafe"; -import createNetworkLogger from "../../helpers/networkLogger/index.js"; -import createFixture from "../../helpers/createFixture/index.js"; -import createConsoleLogger from "../../helpers/consoleLogger/index.js"; -import { CONSENT_OUT } from "../../helpers/constants/consent.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; -import reloadPage from "../../helpers/reloadPage.js"; - -const networkLogger = createNetworkLogger(); - -createFixture({ - title: "C14409 - Consenting to no purposes should be persisted.", - requestHooks: [networkLogger.edgeEndpointLogs], -}); - -test.meta({ - ID: "C14409", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -const config = { - datastreamId: "9999999", - orgId: "53A16ACB5CC1D3760A495C99@AdobeOrg", - defaultConsent: "pending", - idMigrationEnabled: false, - debugEnabled: true, -}; - -test("C14409 - Consenting to no purposes should be persisted.", async () => { - const alloy = createAlloyProxy(); - await alloy.configure(config); - await alloy.setConsent(CONSENT_OUT); - // Reload page and reconfigure alloy - // [TODO] Navigate to a different subdomain when it is available - // https://github.com/DevExpress/testcafe/blob/a4f6a4ac3627ebeb29b344ed3a1793627dd87909/docs/articles/documentation/test-api/actions/navigate.md - await reloadPage(); - - await alloy.configure(config); - const logger = await createConsoleLogger(); - await alloy.sendEvent(); - await logger.warn.expectMessageMatching(/user declined consent/); - await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(0); -}); diff --git a/packages/core/test/functional/specs/Consent/C14410.js b/packages/core/test/functional/specs/Consent/C14410.js deleted file mode 100644 index 6e0319f7d..000000000 --- a/packages/core/test/functional/specs/Consent/C14410.js +++ /dev/null @@ -1,72 +0,0 @@ -/* -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 createFixture from "../../helpers/createFixture/index.js"; -import orgMainConfigMain from "../../helpers/constants/configParts/orgMainConfigMain.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; -import { CONSENT_IN } from "../../helpers/constants/consent.js"; - -createFixture({ - title: - 'C14410: Setting consent for other purposes, or to other values than "in" or "out" should fail', -}); - -test.meta({ - ID: "C14410", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -// This test was originally designed to be done using one test case. When the configure command fails -// from the validation to make sure that only once instance has a particular orgId, the validation -// state isn't reset, so when I had this all in one test, the third part here was failing because -// an instance was already configured with that orgId. - -test("Test C14410: Configuring default consent to 'unknown' fails", async (t) => { - const alloy = createAlloyProxy(); - const errorMessage = await alloy.configureErrorMessage({ - defaultConsent: "unknown", - ...orgMainConfigMain, - }); - await t - .expect(errorMessage) - .ok("Expected the configure command to be rejected"); - await t.expect(errorMessage).contains("'defaultConsent':"); - await t - .expect(errorMessage) - .contains( - `Expected one of these values: ["in","out","pending"], but got "unknown"`, - ); -}); - -test("Test C14410: Setting consent for unknown purposes fails", async (t) => { - const alloy = createAlloyProxy(); - await alloy.configure({ - defaultConsent: "pending", - ...orgMainConfigMain, - }); - const errorMessage = alloy.setConsentErrorMessage({ - consent: [ - { standard: "Adobe", version: "1.0", value: { analytics: "in" } }, - ], - }); - await t - .expect(errorMessage) - .ok("Expected the setConsent command to be rejected"); - await t - .expect(errorMessage) - .contains("The server responded with a status code 400") - .expect(errorMessage) - .contains("EXEG-0102-400"); - - // make sure we can call it again with the correct values - await alloy.setConsent(CONSENT_IN); -}); diff --git a/packages/core/test/functional/specs/Consent/C14411.js b/packages/core/test/functional/specs/Consent/C14411.js deleted file mode 100644 index 3251b1079..000000000 --- a/packages/core/test/functional/specs/Consent/C14411.js +++ /dev/null @@ -1,55 +0,0 @@ -/* -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 createFixture from "../../helpers/createFixture/index.js"; -import { - compose, - orgMainConfigMain, - consentPending, -} from "../../helpers/constants/configParts/index.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; -import { CONSENT_OUT } from "../../helpers/constants/consent.js"; -import { MAIN_CONSENT_COOKIE_NAME } from "../../helpers/constants/cookies.js"; -import cookies from "../../helpers/cookies.js"; -import reloadPage from "../../helpers/reloadPage.js"; - -const config = compose(orgMainConfigMain, consentPending); - -createFixture({ - title: "C14411: User consents to no purposes after consenting to no purposes", -}); - -test.meta({ - ID: "C14411", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -test("Test C14411: User consents to no purposes after consenting to no purposes with cache", async () => { - const alloy = createAlloyProxy(); - await alloy.configure(config); - await alloy.setConsent(CONSENT_OUT); - // make sure this doesn't throw an error - await alloy.setConsent(CONSENT_OUT); -}); - -test("Test C14411: User consents to no purposes after consenting to no purposes without cache", async () => { - const alloy = createAlloyProxy(); - await alloy.configure(config); - await alloy.setConsent(CONSENT_OUT); - - await reloadPage(); - await cookies.remove(MAIN_CONSENT_COOKIE_NAME); - - await alloy.configure(config); - // make sure this doesn't throw an error - await alloy.setConsent(CONSENT_OUT); -}); diff --git a/packages/core/test/functional/specs/Consent/C14414.js b/packages/core/test/functional/specs/Consent/C14414.js deleted file mode 100644 index 90392f785..000000000 --- a/packages/core/test/functional/specs/Consent/C14414.js +++ /dev/null @@ -1,68 +0,0 @@ -/* -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 createFixture from "../../helpers/createFixture/index.js"; -import { - compose, - orgMainConfigMain, - consentPending, - debugEnabled, -} from "../../helpers/constants/configParts/index.js"; -import { CONSENT_IN, CONSENT_OUT } from "../../helpers/constants/consent.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; -import createNetworkLogger from "../../helpers/networkLogger/index.js"; -import SequentialHook from "../../helpers/requestHooks/sequentialHook.js"; - -const config = compose(orgMainConfigMain, consentPending, debugEnabled); - -const networkLogger = createNetworkLogger(); - -createFixture({ - title: "C14414: Requests are queued while consent changes are pending", - requestHooks: [networkLogger.edgeEndpointLogs], -}); - -test.meta({ - ID: "C14414", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -test - .before(async (t) => { - // Create the hook here so that it is only used for one test run. - t.ctx.setConsentHook = new SequentialHook(/v1\/privacy\/set-consent\?/); - await t.addRequestHooks(t.ctx.setConsentHook); - }) - .after(async (t) => { - await t.removeRequestHooks(t.ctx.setConsentHook); - })( - "Test C14414: Requests are queued while consent changes are pending", - async (t) => { - const alloy = createAlloyProxy(); - await alloy.configure(config); - const setConsentResponse1 = await alloy.setConsentAsync(CONSENT_IN); - const setConsentResponse2 = await alloy.setConsentAsync(CONSENT_OUT); - await alloy.sendEvent(); - - // make sure there are no errors returned from the setConsent requests - await setConsentResponse1.result; - await setConsentResponse2.result; - - // make sure the event was not sent - await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(0); - - await t - .expect(t.ctx.setConsentHook.haveRequestsBeenSequential()) - .ok("Set-consent requests were not sequential"); - await t.expect(t.ctx.setConsentHook.getNumRequests()).eql(2); - }, -); diff --git a/packages/core/test/functional/specs/Consent/C1472433.js b/packages/core/test/functional/specs/Consent/C1472433.js deleted file mode 100644 index 691972d8a..000000000 --- a/packages/core/test/functional/specs/Consent/C1472433.js +++ /dev/null @@ -1,59 +0,0 @@ -/* -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 } from "testcafe"; -import createFixture from "../../helpers/createFixture/index.js"; -import createNetworkLogger from "../../helpers/networkLogger/index.js"; -import orgMainConfigMain from "../../helpers/constants/configParts/orgMainConfigMain.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; -import reloadPage from "../../helpers/reloadPage.js"; -import { ADOBE2_IN } from "../../helpers/constants/consent.js"; - -const networkLogger = createNetworkLogger(); - -createFixture({ - title: "C1472433: Set-consent is not called when consent is the same", - requestHooks: [ - networkLogger.setConsentEndpointLogs, - networkLogger.edgeInteractEndpointLogs, - ], -}); - -test.meta({ - ID: "C1472433", - SEVERITY: "P0", - TEST_RUN: "REGRESSION", -}); - -const configuration = { - defaultConsent: "pending", - ...orgMainConfigMain, -}; - -test("C1472433 - Set-consent is not called when consent is the same", async () => { - // set consent to in - const alloy = createAlloyProxy(); - await alloy.configure(configuration); - await alloy.setConsent(ADOBE2_IN); - await t.expect(networkLogger.setConsentEndpointLogs.requests.length).eql(1); - - // reload the page to make sure the hashes are stored - await reloadPage(); - await alloy.configure(configuration); - - // send an event which should go out immediately - await alloy.sendEvent(); - await t.expect(networkLogger.edgeInteractEndpointLogs.requests.length).eql(1); - - // set the consent to in again, and make sure an edge request isn't generated. - await alloy.setConsent(ADOBE2_IN); - await t.expect(networkLogger.setConsentEndpointLogs.requests.length).eql(1); -}); diff --git a/packages/core/test/functional/specs/Consent/C1472434.js b/packages/core/test/functional/specs/Consent/C1472434.js deleted file mode 100644 index 975e55c3c..000000000 --- a/packages/core/test/functional/specs/Consent/C1472434.js +++ /dev/null @@ -1,59 +0,0 @@ -/* -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 } from "testcafe"; -import createFixture from "../../helpers/createFixture/index.js"; -import createNetworkLogger from "../../helpers/networkLogger/index.js"; -import orgMainConfigMain from "../../helpers/constants/configParts/orgMainConfigMain.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; -import reloadPage from "../../helpers/reloadPage.js"; -import { ADOBE2_IN, ADOBE2_OUT } from "../../helpers/constants/consent.js"; - -const networkLogger = createNetworkLogger(); - -createFixture({ - title: "C1472434: Set-consent is called when consent is different", - requestHooks: [ - networkLogger.setConsentEndpointLogs, - networkLogger.edgeInteractEndpointLogs, - ], -}); - -test.meta({ - ID: "C1472434", - SEVERITY: "P0", - TEST_RUN: "REGRESSION", -}); - -const configuration = { - defaultConsent: "pending", - ...orgMainConfigMain, -}; - -test("C1472434: Set-consent is called when consent is different", async () => { - // set consent to in - const alloy = createAlloyProxy(); - await alloy.configure(configuration); - await alloy.setConsent(ADOBE2_IN); - await t.expect(networkLogger.setConsentEndpointLogs.requests.length).eql(1); - - // reload the page to make sure the hashes are stored and not just in memory - await reloadPage(); - await alloy.configure(configuration); - - // send an event which should go out immediately - await alloy.sendEvent(); - await t.expect(networkLogger.edgeInteractEndpointLogs.requests.length).eql(1); - - // set the consent on Alloy, and make sure it generates a new edge request - await alloy.setConsent(ADOBE2_OUT); - await t.expect(networkLogger.setConsentEndpointLogs.requests.length).eql(2); -}); diff --git a/packages/core/test/functional/specs/Consent/C1472435.js b/packages/core/test/functional/specs/Consent/C1472435.js deleted file mode 100644 index f59454002..000000000 --- a/packages/core/test/functional/specs/Consent/C1472435.js +++ /dev/null @@ -1,73 +0,0 @@ -/* -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 } from "testcafe"; -import createFixture from "../../helpers/createFixture/index.js"; -import createNetworkLogger from "../../helpers/networkLogger/index.js"; -import orgMainConfigMain from "../../helpers/constants/configParts/orgMainConfigMain.js"; -import reloadPage from "../../helpers/reloadPage.js"; -import flushPromiseChains from "../../helpers/flushPromiseChains.js"; -import cookies from "../../helpers/cookies.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; -import { - LEGACY_IDENTITY_COOKIE_NAME, - MAIN_IDENTITY_COOKIE_NAME, -} from "../../helpers/constants/cookies.js"; -import { ADOBE2_IN } from "../../helpers/constants/consent.js"; - -const networkLogger = createNetworkLogger(); - -createFixture({ - title: - "C1472435: Set-consent is called when identity cookie is missing even though consent is the same", - requestHooks: [ - networkLogger.setConsentEndpointLogs, - networkLogger.edgeInteractEndpointLogs, - ], -}); - -test.meta({ - ID: "C1472435", - SEVERITY: "P0", - TEST_RUN: "REGRESSION", -}); - -const configuration = { - defaultConsent: "pending", - ...orgMainConfigMain, -}; - -test("C1472435: Set-consent is called when identity cookie is missing even though consent is the same", async () => { - // set consent to in - const alloy = createAlloyProxy(); - await alloy.configure(configuration); - await alloy.setConsent(ADOBE2_IN); - await t.expect(networkLogger.setConsentEndpointLogs.requests.length).eql(1); - - // delete identity cookie, and reload - await reloadPage(); - await cookies.remove(MAIN_IDENTITY_COOKIE_NAME); - await cookies.remove(LEGACY_IDENTITY_COOKIE_NAME); - await alloy.configure(configuration); - - // try to send an event, but it should be queued - const sendEventResponse = await alloy.sendEventAsync(); - await flushPromiseChains(); - await t.expect(networkLogger.edgeInteractEndpointLogs.requests.length).eql(0); - - // set the consent to IN - await alloy.setConsent(ADOBE2_IN); - await t.expect(networkLogger.setConsentEndpointLogs.requests.length).eql(2); - - // make sure the event goes out - await sendEventResponse.result; - await t.expect(networkLogger.edgeInteractEndpointLogs.requests.length).eql(1); -}); diff --git a/packages/core/test/functional/specs/Consent/C1472436.js b/packages/core/test/functional/specs/Consent/C1472436.js deleted file mode 100644 index eb94ea742..000000000 --- a/packages/core/test/functional/specs/Consent/C1472436.js +++ /dev/null @@ -1,70 +0,0 @@ -/* -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 } from "testcafe"; -import createFixture from "../../helpers/createFixture/index.js"; -import createNetworkLogger from "../../helpers/networkLogger/index.js"; -import orgMainConfigMain from "../../helpers/constants/configParts/orgMainConfigMain.js"; -import reloadPage from "../../helpers/reloadPage.js"; -import flushPromiseChains from "../../helpers/flushPromiseChains.js"; -import cookies from "../../helpers/cookies.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; -import { ADOBE2_IN } from "../../helpers/constants/consent.js"; -import { MAIN_CONSENT_COOKIE_NAME } from "../../helpers/constants/cookies.js"; - -const networkLogger = createNetworkLogger(); - -createFixture({ - title: - "C1472436: Set-consent is called when consent cookie is missing even though consent is the same", - requestHooks: [ - networkLogger.setConsentEndpointLogs, - networkLogger.edgeInteractEndpointLogs, - ], -}); - -test.meta({ - ID: "C1472436", - SEVERITY: "P0", - TEST_RUN: "REGRESSION", -}); - -const configuration = { - defaultConsent: "pending", - debugEnabled: true, - ...orgMainConfigMain, -}; - -test("C1472436: Set-consent is called when consent cookie is missing even though consent is the same", async () => { - // set consent to in - const alloy = createAlloyProxy(); - await alloy.configure(configuration); - await alloy.setConsent(ADOBE2_IN); - await t.expect(networkLogger.setConsentEndpointLogs.requests.length).eql(1); - - // delete consent cookie, and reload - await reloadPage(); - await cookies.remove(MAIN_CONSENT_COOKIE_NAME); - await alloy.configure(configuration); - - // try to send an event, but it should be queued - const sendEventResponse = await alloy.sendEventAsync(); - await flushPromiseChains(); - await t.expect(networkLogger.edgeInteractEndpointLogs.requests.length).eql(0); - - // set the consent to IN - await alloy.setConsent(ADOBE2_IN); - await t.expect(networkLogger.setConsentEndpointLogs.requests.length).eql(2); - - // make sure the event goes out - await sendEventResponse.result; - await t.expect(networkLogger.edgeInteractEndpointLogs.requests.length).eql(1); -}); diff --git a/packages/core/test/functional/specs/Consent/C1472437.js b/packages/core/test/functional/specs/Consent/C1472437.js deleted file mode 100644 index 092eeee48..000000000 --- a/packages/core/test/functional/specs/Consent/C1472437.js +++ /dev/null @@ -1,58 +0,0 @@ -/* -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 } from "testcafe"; -import createFixture from "../../helpers/createFixture/index.js"; -import createNetworkLogger from "../../helpers/networkLogger/index.js"; -import orgMainConfigMain from "../../helpers/constants/configParts/orgMainConfigMain.js"; -import flushPromiseChains from "../../helpers/flushPromiseChains.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; -import { ADOBE2_IN } from "../../helpers/constants/consent.js"; - -const networkLogger = createNetworkLogger(); - -createFixture({ - title: "C1472437: Adobe consent version 2.0 is translated to general=in", - requestHooks: [ - networkLogger.setConsentEndpointLogs, - networkLogger.edgeInteractEndpointLogs, - ], -}); - -test.meta({ - ID: "C1472437", - SEVERITY: "P0", - TEST_RUN: "REGRESSION", -}); - -const configuration = { - defaultConsent: "pending", - ...orgMainConfigMain, -}; - -test("C1472437: Adobe consent version 2.0 is translated to general=in", async () => { - // setup alloy - const alloy = createAlloyProxy(); - await alloy.configure(configuration); - - // try to send an event, but it should be queued - const sendEventResponse = await alloy.sendEventAsync(); - await flushPromiseChains(); - await t.expect(networkLogger.edgeInteractEndpointLogs.requests.length).eql(0); - - // set the consent to IN - await alloy.setConsent(ADOBE2_IN); - await t.expect(networkLogger.setConsentEndpointLogs.requests.length).eql(1); - - // make sure the event goes out - await sendEventResponse.result; - await t.expect(networkLogger.edgeInteractEndpointLogs.requests.length).eql(1); -}); diff --git a/packages/core/test/functional/specs/Consent/C1472438.js b/packages/core/test/functional/specs/Consent/C1472438.js deleted file mode 100644 index d4dd14e6b..000000000 --- a/packages/core/test/functional/specs/Consent/C1472438.js +++ /dev/null @@ -1,58 +0,0 @@ -/* -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 } from "testcafe"; -import createFixture from "../../helpers/createFixture/index.js"; -import createNetworkLogger from "../../helpers/networkLogger/index.js"; -import orgMainConfigMain from "../../helpers/constants/configParts/orgMainConfigMain.js"; -import flushPromiseChains from "../../helpers/flushPromiseChains.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; -import { ADOBE2_OUT } from "../../helpers/constants/consent.js"; - -const networkLogger = createNetworkLogger(); - -createFixture({ - title: "C1472438: Adobe consent version 2.0 is translated to general=out", - requestHooks: [ - networkLogger.setConsentEndpointLogs, - networkLogger.edgeInteractEndpointLogs, - ], -}); - -test.meta({ - ID: "C1472438", - SEVERITY: "P0", - TEST_RUN: "REGRESSION", -}); - -const configuration = { - defaultConsent: "pending", - ...orgMainConfigMain, -}; - -test("C1472438: Adobe consent version 2.0 is translated to general=out", async () => { - // setup alloy - const alloy = createAlloyProxy(); - await alloy.configure(configuration); - - // try to send an event, but it should be queued - const sendEventResponse = await alloy.sendEventAsync(); - await flushPromiseChains(); - await t.expect(networkLogger.edgeInteractEndpointLogs.requests.length).eql(0); - - // set the consent to OUT - await alloy.setConsent(ADOBE2_OUT); - await t.expect(networkLogger.setConsentEndpointLogs.requests.length).eql(1); - - // make sure the event does not go out - await sendEventResponse.result; - await t.expect(networkLogger.edgeInteractEndpointLogs.requests.length).eql(0); -}); diff --git a/packages/core/test/functional/specs/Consent/C1576777.js b/packages/core/test/functional/specs/Consent/C1576777.js deleted file mode 100644 index f8d84df7b..000000000 --- a/packages/core/test/functional/specs/Consent/C1576777.js +++ /dev/null @@ -1,70 +0,0 @@ -/* -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 } from "testcafe"; -import createFixture from "../../helpers/createFixture/index.js"; -import createNetworkLogger from "../../helpers/networkLogger/index.js"; -import orgMainConfigMain from "../../helpers/constants/configParts/orgMainConfigMain.js"; -import reloadPage from "../../helpers/reloadPage.js"; -import cookies from "../../helpers/cookies.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; -import { - LEGACY_IDENTITY_COOKIE_NAME, - MAIN_IDENTITY_COOKIE_NAME, -} from "../../helpers/constants/cookies.js"; -import { ADOBE2_OUT } from "../../helpers/constants/consent.js"; - -const networkLogger = createNetworkLogger(); - -createFixture({ - title: "C1576777: When identity cookie is missing, stored consent is cleared", - requestHooks: [ - networkLogger.setConsentEndpointLogs, - networkLogger.edgeInteractEndpointLogs, - ], -}); - -test.meta({ - ID: "C1576777", - SEVERITY: "P0", - TEST_RUN: "REGRESSION", -}); - -const configuration = { - defaultConsent: "in", - debugEnabled: true, - idMigrationEnabled: true, - thirdPartyCookiesEnabled: false, - ...orgMainConfigMain, -}; - -test.skip("C1576777: When identity cookie is missing, stored consent is cleared", async () => { - // set consent to out - const alloy = createAlloyProxy(); - await alloy.configure(configuration); - await alloy.setConsent(ADOBE2_OUT); - - // delete identity cookie, and reload - await reloadPage(); - await cookies.remove(MAIN_IDENTITY_COOKIE_NAME); - await cookies.remove(LEGACY_IDENTITY_COOKIE_NAME); - await alloy.configure(configuration); - - // try to send an event it should go out since the stored consent should be cleared - await alloy.sendEvent(); - - // reload again because now we have an identity cookie - await reloadPage(); - await alloy.configure(configuration); - await alloy.sendEvent(); - - await t.expect(networkLogger.edgeInteractEndpointLogs.requests.length).eql(2); -}); diff --git a/packages/core/test/functional/specs/Consent/C1631712.js b/packages/core/test/functional/specs/Consent/C1631712.js deleted file mode 100644 index 027052f07..000000000 --- a/packages/core/test/functional/specs/Consent/C1631712.js +++ /dev/null @@ -1,60 +0,0 @@ -/* -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 createFixture from "../../helpers/createFixture/index.js"; -import { - compose, - orgMainConfigMain, - debugEnabled, -} from "../../helpers/constants/configParts/index.js"; -import { CONSENT_IN } from "../../helpers/constants/consent.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; -import createNetworkLogger from "../../helpers/networkLogger/index.js"; -import flushPromiseChains from "../../../unit/helpers/flushPromiseChains.js"; -import createConsoleLogger from "../../helpers/consoleLogger/index.js"; - -const config = compose( - orgMainConfigMain, - { defaultConsent: "out" }, - debugEnabled, -); - -const networkLogger = createNetworkLogger(); - -createFixture({ - title: "C1631712: Requests are dropped when default consent is out", - requestHooks: [networkLogger.edgeEndpointLogs], -}); - -test.meta({ - ID: "C1631712", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -test("Test C1631712: Requests are dropped when default consent is out", async (t) => { - const alloy = createAlloyProxy(); - await alloy.configure(config); - const logger = await createConsoleLogger(); - - const result = await alloy.sendEvent(); - await t.expect(result).eql({}); - await logger.warn.expectMessageMatching( - /No consent preferences have been set./, - ); - - await alloy.setConsent(CONSENT_IN); - await flushPromiseChains(); - await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(0); - - await alloy.sendEvent(); - await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(1); -}); diff --git a/packages/core/test/functional/specs/Consent/C225953.js b/packages/core/test/functional/specs/Consent/C225953.js deleted file mode 100644 index 177033644..000000000 --- a/packages/core/test/functional/specs/Consent/C225953.js +++ /dev/null @@ -1,54 +0,0 @@ -/* -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 createFixture from "../../helpers/createFixture/index.js"; -import createNetworkLogger from "../../helpers/networkLogger/index.js"; -import { responseStatus } from "../../helpers/assertions/index.js"; - -import { - compose, - orgMainConfigMain, - consentPending, - debugEnabled, -} from "../../helpers/constants/configParts/index.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; -import { CONSENT_IN } from "../../helpers/constants/consent.js"; - -const config = compose(orgMainConfigMain, consentPending, debugEnabled); - -const networkLogger = createNetworkLogger(); - -createFixture({ - title: "C225953: Identity map can be sent on a setConsent command", - requestHooks: [networkLogger.edgeEndpointLogs], -}); - -test.meta({ - ID: "C225953", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -test("Test C225953: Identity map can be sent on a setConsent command", async () => { - const alloy = createAlloyProxy(); - await alloy.configure(config); - await alloy.setConsent({ - identityMap: { - HYP: [ - { - id: "id123", - }, - ], - }, - consent: CONSENT_IN.consent, - }); - await responseStatus(networkLogger.edgeEndpointLogs.requests, [200, 207]); -}); diff --git a/packages/core/test/functional/specs/Consent/C25148.js b/packages/core/test/functional/specs/Consent/C25148.js deleted file mode 100644 index 634c00234..000000000 --- a/packages/core/test/functional/specs/Consent/C25148.js +++ /dev/null @@ -1,60 +0,0 @@ -/* -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 } from "testcafe"; -import createNetworkLogger from "../../helpers/networkLogger/index.js"; -import createFixture from "../../helpers/createFixture/index.js"; -import createConsoleLogger from "../../helpers/consoleLogger/index.js"; -import { - compose, - debugEnabled, - orgMainConfigMain, -} from "../../helpers/constants/configParts/index.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; -import { CONSENT_OUT } from "../../helpers/constants/consent.js"; - -const networkLogger = createNetworkLogger(); - -createFixture({ - title: "C25148 - When default consent is 'in', consent can be revoked.", - requestHooks: [networkLogger.edgeEndpointLogs], -}); - -test.meta({ - ID: "C25148", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -const config = compose(orgMainConfigMain, debugEnabled); - -test("C25148 - When default consent is 'in', consent can be revoked", async () => { - const alloy = createAlloyProxy(); - await alloy.configure(config); - - // trigger an event - await alloy.sendEvent(); - - // revoke user consent - await alloy.setConsent(CONSENT_OUT); - - // trigger a second event - const logger = await createConsoleLogger(); - await alloy.sendEvent(); - await logger.warn.expectMessageMatching(/user declined consent/); - - // ensure only one event was sent - await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(1); - const stringifyRequest = JSON.parse( - networkLogger.edgeEndpointLogs.requests[0].request.body, - ); - await t.expect(stringifyRequest.events.length).eql(1); -}); diff --git a/packages/core/test/functional/specs/Consent/C2593.js b/packages/core/test/functional/specs/Consent/C2593.js deleted file mode 100644 index 8362c2412..000000000 --- a/packages/core/test/functional/specs/Consent/C2593.js +++ /dev/null @@ -1,52 +0,0 @@ -/* -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 } from "testcafe"; -import createNetworkLogger from "../../helpers/networkLogger/index.js"; -import { responseStatus } from "../../helpers/assertions/index.js"; -import createFixture from "../../helpers/createFixture/index.js"; -import environmentContextConfig from "../../helpers/constants/environmentContextConfig.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; -import flushPromiseChains from "../../helpers/flushPromiseChains.js"; -import { CONSENT_IN } from "../../helpers/constants/consent.js"; - -const networkLogger = createNetworkLogger(); - -createFixture({ - title: "C2593: Event command sets consent to in.", - requestHooks: [networkLogger.edgeEndpointLogs], -}); - -test.meta({ - ID: "C2593", - SEVERITY: "P0", - TEST_RUN: "REGRESSION", -}); - -test("Test C2593: Event command consents to all purposes", async () => { - const alloy = createAlloyProxy(); - await alloy.configure({ - defaultConsent: "pending", - ...environmentContextConfig, - }); - // try to send an event and verify that it is queued - const sendEventResponse = await alloy.sendEventAsync(); - await flushPromiseChains(); - await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(0); - - // set the consent to in - await alloy.setConsent(CONSENT_IN); - - // ensure the event goes out - await sendEventResponse.result; - await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(1); - await responseStatus(networkLogger.edgeEndpointLogs.requests, [200, 207]); -}); diff --git a/packages/core/test/functional/specs/Consent/C2594.js b/packages/core/test/functional/specs/Consent/C2594.js deleted file mode 100644 index 244e5b4e1..000000000 --- a/packages/core/test/functional/specs/Consent/C2594.js +++ /dev/null @@ -1,53 +0,0 @@ -/* -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 createFixture from "../../helpers/createFixture/index.js"; -import createNetworkLogger from "../../helpers/networkLogger/index.js"; -import { - compose, - orgMainConfigMain, - consentPending, - debugEnabled, -} from "../../helpers/constants/configParts/index.js"; -import createConsoleLogger from "../../helpers/consoleLogger/index.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; -import { CONSENT_OUT } from "../../helpers/constants/consent.js"; - -const config = compose(orgMainConfigMain, consentPending, debugEnabled); - -const networkLogger = createNetworkLogger(); - -createFixture({ - title: - "C2594: event command resolves promise with empty object if user consents to no purposes", - requestHooks: [networkLogger.edgeEndpointLogs], -}); - -test.meta({ - ID: "C2594", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -test("Test C2594: event command resolves promise with empty object if user consents to no purposes", async (t) => { - const alloy = createAlloyProxy(); - await alloy.configure(config); - const logger = await createConsoleLogger(); - - const sendEventResponse = await alloy.sendEventAsync(); - await alloy.setConsent(CONSENT_OUT); - - const result = await sendEventResponse.result; - await t.expect(result).eql({}); - await logger.warn.expectMessageMatching(/The user declined consent./); - // make sure no event requests were sent out - await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(0); -}); diff --git a/packages/core/test/functional/specs/Consent/C2660.js b/packages/core/test/functional/specs/Consent/C2660.js deleted file mode 100644 index 9eaf3032a..000000000 --- a/packages/core/test/functional/specs/Consent/C2660.js +++ /dev/null @@ -1,70 +0,0 @@ -/* -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 } from "testcafe"; -import createNetworkLogger from "../../helpers/networkLogger/index.js"; -import createFixture from "../../helpers/createFixture/index.js"; -import flushPromiseChains from "../../helpers/flushPromiseChains.js"; -import orgMainConfigMain from "../../helpers/constants/configParts/orgMainConfigMain.js"; -import { - compose, - consentPending, -} from "../../helpers/constants/configParts/index.js"; -import { TEST_PAGE as TEST_PAGE_URL } from "../../helpers/constants/url.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; -import { CONSENT_IN } from "../../helpers/constants/consent.js"; - -const networkLogger = createNetworkLogger(); - -createFixture({ - title: "C2660 - Context data is captured before user consents.", - requestHooks: [networkLogger.edgeEndpointLogs], -}); - -test.meta({ - ID: "C2660", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -const getContextUrlFromRequest = (request) => { - const parsedBody = JSON.parse(request.request.body); - return parsedBody.events[0].xdm.web.webPageDetails.URL; -}; - -test("C2660 - Context data is captured before user consents.", async () => { - const alloy = createAlloyProxy(); - await alloy.configure(compose(orgMainConfigMain, consentPending)); - - // send an event that will be queued - const sendEventResponse = await alloy.sendEventAsync(); - await flushPromiseChains(); - - // change something that will be collected by Context Component - await t.eval(() => { - window.location.hash = "foo"; - }); - - // set consent to flush the events queue - await alloy.setConsent(CONSENT_IN); - await sendEventResponse.result; - - // send another event to make sure the foo hash is collected normally - await alloy.sendEvent(); - - // expect that context was captured at the right time - await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(2); - const requests = networkLogger.edgeEndpointLogs.requests; - await t.expect(getContextUrlFromRequest(requests[0])).eql(TEST_PAGE_URL); - await t - .expect(getContextUrlFromRequest(requests[1])) - .eql(`${TEST_PAGE_URL}#foo`); -}); diff --git a/packages/core/test/functional/specs/Consent/C28754.js b/packages/core/test/functional/specs/Consent/C28754.js deleted file mode 100644 index 2d72fa229..000000000 --- a/packages/core/test/functional/specs/Consent/C28754.js +++ /dev/null @@ -1,68 +0,0 @@ -/* -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 } from "testcafe"; -import createNetworkLogger from "../../helpers/networkLogger/index.js"; -import { responseStatus } from "../../helpers/assertions/index.js"; -import createFixture from "../../helpers/createFixture/index.js"; -import createResponse from "../../helpers/createResponse.js"; -import getResponseBody from "../../helpers/networkLogger/getResponseBody.js"; -import { - compose, - orgMainConfigMain, - consentPending, -} from "../../helpers/constants/configParts/index.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; - -import { CONSENT_OUT } from "../../helpers/constants/consent.js"; - -const config = compose(orgMainConfigMain, consentPending); - -const networkLogger = createNetworkLogger(); - -createFixture({ - title: - "C28754 - Consenting to no purposes should result in no data handles in the response.", - requestHooks: [networkLogger.setConsentEndpointLogs], -}); - -test.meta({ - ID: "C28754", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -test("C28754 - Consenting to no purposes should result in no data handles in the response.", async () => { - const alloy = createAlloyProxy(); - await alloy.configure(config); - - await alloy.setConsent(CONSENT_OUT); - await responseStatus( - networkLogger.setConsentEndpointLogs.requests, - [200, 207], - ); - - const response = JSON.parse( - getResponseBody(networkLogger.setConsentEndpointLogs.requests[0]), - ); - - const alloyResponse = createResponse({ content: response }); - - const idSyncsPayload = alloyResponse.getPayloadsByType("identity:exchange"); - const personalizationPayload = alloyResponse.getPayloadsByType( - "personalization:decisions", - ); - const audiencesPayload = alloyResponse.getPayloadsByType("activation:push"); - - await t.expect(idSyncsPayload).eql([]); - await t.expect(personalizationPayload).eql([]); - await t.expect(audiencesPayload).eql([]); -}); diff --git a/packages/core/test/functional/specs/Consent/C5594870.js b/packages/core/test/functional/specs/Consent/C5594870.js deleted file mode 100644 index 4c47d7196..000000000 --- a/packages/core/test/functional/specs/Consent/C5594870.js +++ /dev/null @@ -1,61 +0,0 @@ -/* -Copyright 2022 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 } from "testcafe"; -import createFixture from "../../helpers/createFixture/index.js"; -import { - compose, - orgMainConfigMain, - debugEnabled, -} from "../../helpers/constants/configParts/index.js"; -import createNetworkLogger from "../../helpers/networkLogger/index.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; -import createRandomEcid from "../../helpers/createRandomEcid.js"; -import { TEST_PAGE as TEST_PAGE_URL } from "../../helpers/constants/url.js"; -import { CONSENT_IN } from "../../helpers/constants/consent.js"; -import getReturnedEcid from "../../helpers/networkLogger/getReturnedEcid.js"; -import createAdobeMC from "../../helpers/createAdobeMC.js"; - -const config = compose( - orgMainConfigMain, - { defaultConsent: "pending" }, - debugEnabled, -); - -const networkLogger = createNetworkLogger(); - -const id = createRandomEcid(); -const adobemc = createAdobeMC({ id }); - -createFixture({ - url: `${TEST_PAGE_URL}?adobe_mc=${adobemc}`, - title: - "C5594870: Identity can be set via the adobe_mc query string parameter when calling set-consent", - requestHooks: [networkLogger.setConsentEndpointLogs], -}); - -test.meta({ - ID: "C5594870", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -test("C5594870: Identity can be set via the adobe_mc query string parameter when calling set-consent", async () => { - const alloy = createAlloyProxy(); - await alloy.configure(config); - - await alloy.setConsent(CONSENT_IN); - const ecid = getReturnedEcid( - networkLogger.setConsentEndpointLogs.requests[0], - ); - await t.expect(ecid).eql(id); -}); diff --git a/packages/core/test/functional/specs/Consent/IAB/C224670.js b/packages/core/test/functional/specs/Consent/IAB/C224670.js deleted file mode 100644 index aa1c47999..000000000 --- a/packages/core/test/functional/specs/Consent/IAB/C224670.js +++ /dev/null @@ -1,74 +0,0 @@ -/* -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 } from "testcafe"; -import createNetworkLogger from "../../../helpers/networkLogger/index.js"; -import { responseStatus } from "../../../helpers/assertions/index.js"; -import createFixture from "../../../helpers/createFixture/index.js"; -import createResponse from "../../../helpers/createResponse.js"; -import getResponseBody from "../../../helpers/networkLogger/getResponseBody.js"; -import cookies from "../../../helpers/cookies.js"; -import { - compose, - orgMainConfigMain, - consentPending, - debugEnabled, -} from "../../../helpers/constants/configParts/index.js"; -import { MAIN_CONSENT_COOKIE_NAME } from "../../../helpers/constants/cookies.js"; -import createAlloyProxy from "../../../helpers/createAlloyProxy.js"; -import { IAB_CONSENT_IN } from "../../../helpers/constants/consent.js"; - -const config = compose(orgMainConfigMain, consentPending, debugEnabled); - -const networkLogger = createNetworkLogger(); - -createFixture({ - title: "C224670: Opt in to IAB using the setConsent command.", - requestHooks: [ - networkLogger.setConsentEndpointLogs, - networkLogger.edgeEndpointLogs, - ], -}); - -test.meta({ - ID: "C224670", - SEVERITY: "P0", - TEST_RUN: "REGRESSION", -}); - -test("Test C224670: Opt in to IAB", async () => { - const alloy = createAlloyProxy(); - await alloy.configure(config); - await alloy.setConsent(IAB_CONSENT_IN); - - await t.expect(networkLogger.setConsentEndpointLogs.requests.length).eql(1); - await responseStatus(networkLogger.edgeEndpointLogs.requests, [200, 207]); - - const consentRawResponse = JSON.parse( - getResponseBody(networkLogger.setConsentEndpointLogs.requests[0]), - ); - - const consentResponse = createResponse({ content: consentRawResponse }); - - // 1. The set-consent response should contain the Consent cookie: { general: in } - const consentCookieValue = await cookies.get(MAIN_CONSENT_COOKIE_NAME); - - await t.expect(consentCookieValue).ok("No consent cookie found."); - await t.expect(consentCookieValue).eql("general=in"); - - // 2. The ECID should exist in the response payload as well, if queried - const identityHandle = consentResponse.getPayloadsByType("identity:result"); - const returnedNamespaces = identityHandle.map((i) => i.namespace.code); - await t.expect(returnedNamespaces).contains("ECID"); - - await alloy.sendEvent(); - await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(1); -}); diff --git a/packages/core/test/functional/specs/Consent/IAB/C224671.js b/packages/core/test/functional/specs/Consent/IAB/C224671.js deleted file mode 100644 index e62ddea57..000000000 --- a/packages/core/test/functional/specs/Consent/IAB/C224671.js +++ /dev/null @@ -1,79 +0,0 @@ -/* -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 } from "testcafe"; -import createNetworkLogger from "../../../helpers/networkLogger/index.js"; -import { responseStatus } from "../../../helpers/assertions/index.js"; -import createFixture from "../../../helpers/createFixture/index.js"; -import createResponse from "../../../helpers/createResponse.js"; -import getResponseBody from "../../../helpers/networkLogger/getResponseBody.js"; -import cookies from "../../../helpers/cookies.js"; -import { - compose, - orgMainConfigMain, - consentPending, - debugEnabled, -} from "../../../helpers/constants/configParts/index.js"; -import { MAIN_CONSENT_COOKIE_NAME } from "../../../helpers/constants/cookies.js"; -import createAlloyProxy from "../../../helpers/createAlloyProxy.js"; -import { - IAB_NO_PURPOSE_ONE, - IAB_NO_ADOBE_VENDOR, -} from "../../../helpers/constants/consent.js"; - -const config = compose(orgMainConfigMain, consentPending, debugEnabled); - -const networkLogger = createNetworkLogger(); - -createFixture({ - title: "C224671: Opt out of IAB using the setConsent command.", - requestHooks: [ - networkLogger.setConsentEndpointLogs, - networkLogger.edgeEndpointLogs, - ], -}); - -test.meta({ - ID: "C224671", - SEVERITY: "P0", - TEST_RUN: "REGRESSION", -}); - -[IAB_NO_PURPOSE_ONE, IAB_NO_ADOBE_VENDOR].forEach((consent) => { - test("Test C224671: Opt out of IAB - No Purpose 1 & No Vendor", async () => { - const alloy = createAlloyProxy(); - await alloy.configure(config); - await alloy.setConsent(consent); - - await t.expect(networkLogger.setConsentEndpointLogs.requests.length).eql(1); - await responseStatus(networkLogger.edgeEndpointLogs.requests, [200, 207]); - - const consentRawResponse = JSON.parse( - getResponseBody(networkLogger.setConsentEndpointLogs.requests[0]), - ); - - const consentResponse = createResponse({ content: consentRawResponse }); - - // 1. The set-consent response should contain the Consent cookie: { general: out } - const consentCookieValue = await cookies.get(MAIN_CONSENT_COOKIE_NAME); - - await t.expect(consentCookieValue).ok("No consent cookie found."); - await t.expect(consentCookieValue).eql("general=out"); - - // 2. The ECID should exist in the response payload as well, if queried - const identityHandle = consentResponse.getPayloadsByType("identity:result"); - const returnedNamespaces = identityHandle.map((i) => i.namespace.code); - await t.expect(returnedNamespaces).contains("ECID"); - - await alloy.sendEvent(); - await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(0); - }); -}); diff --git a/packages/core/test/functional/specs/Consent/IAB/C224672.js b/packages/core/test/functional/specs/Consent/IAB/C224672.js deleted file mode 100644 index 690ab5976..000000000 --- a/packages/core/test/functional/specs/Consent/IAB/C224672.js +++ /dev/null @@ -1,75 +0,0 @@ -/* -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 } from "testcafe"; -import createNetworkLogger from "../../../helpers/networkLogger/index.js"; -import { responseStatus } from "../../../helpers/assertions/index.js"; -import createFixture from "../../../helpers/createFixture/index.js"; -import createResponse from "../../../helpers/createResponse.js"; -import getResponseBody from "../../../helpers/networkLogger/getResponseBody.js"; -import cookies from "../../../helpers/cookies.js"; -import { - compose, - orgMainConfigMain, - consentPending, - debugEnabled, -} from "../../../helpers/constants/configParts/index.js"; -import { MAIN_CONSENT_COOKIE_NAME } from "../../../helpers/constants/cookies.js"; -import createAlloyProxy from "../../../helpers/createAlloyProxy.js"; -import { IAB_CONSENT_IN_PERSONAL_DATA } from "../../../helpers/constants/consent.js"; - -const config = compose(orgMainConfigMain, consentPending, debugEnabled); - -const networkLogger = createNetworkLogger(); - -createFixture({ - title: - "C224672: Passing the `gdprContainsPersonalData` flag should return in the response.", - requestHooks: [ - networkLogger.setConsentEndpointLogs, - networkLogger.edgeEndpointLogs, - ], -}); - -test.meta({ - ID: "C224672", - SEVERITY: "P0", - TEST_RUN: "REGRESSION", -}); - -test("Test C224672: Passing the `gdprContainsPersonalData` flag should return in the response", async () => { - const alloy = createAlloyProxy(); - await alloy.configure(config); - await alloy.setConsent(IAB_CONSENT_IN_PERSONAL_DATA); - - await t.expect(networkLogger.setConsentEndpointLogs.requests.length).eql(1); - await responseStatus(networkLogger.edgeEndpointLogs.requests, [200, 207]); - - const consentRawResponse = JSON.parse( - getResponseBody(networkLogger.setConsentEndpointLogs.requests[0]), - ); - - const consentResponse = createResponse({ content: consentRawResponse }); - - // 1. The set-consent response should contain the Consent cookie: { general: in } - const consentCookieValue = await cookies.get(MAIN_CONSENT_COOKIE_NAME); - - await t.expect(consentCookieValue).ok("No consent cookie found."); - await t.expect(consentCookieValue).eql("general=in"); - - // 2. The ECID should exist in the response payload as well, if queried - const identityHandle = consentResponse.getPayloadsByType("identity:result"); - const returnedNamespaces = identityHandle.map((i) => i.namespace.code); - await t.expect(returnedNamespaces).contains("ECID"); - - await alloy.sendEvent(); - await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(1); -}); diff --git a/packages/core/test/functional/specs/Consent/IAB/C224673.js b/packages/core/test/functional/specs/Consent/IAB/C224673.js deleted file mode 100644 index 6e832349f..000000000 --- a/packages/core/test/functional/specs/Consent/IAB/C224673.js +++ /dev/null @@ -1,74 +0,0 @@ -/* -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 } from "testcafe"; -import createNetworkLogger from "../../../helpers/networkLogger/index.js"; -import { responseStatus } from "../../../helpers/assertions/index.js"; -import createFixture from "../../../helpers/createFixture/index.js"; -import createResponse from "../../../helpers/createResponse.js"; -import getResponseBody from "../../../helpers/networkLogger/getResponseBody.js"; -import cookies from "../../../helpers/cookies.js"; -import { - compose, - orgMainConfigMain, - consentPending, - debugEnabled, -} from "../../../helpers/constants/configParts/index.js"; -import { MAIN_CONSENT_COOKIE_NAME } from "../../../helpers/constants/cookies.js"; -import createAlloyProxy from "../../../helpers/createAlloyProxy.js"; -import { IAB_CONSENT_IN_NO_GDPR } from "../../../helpers/constants/consent.js"; - -const config = compose(orgMainConfigMain, consentPending, debugEnabled); - -const networkLogger = createNetworkLogger(); - -createFixture({ - title: "C224673: Opt in to IAB while gdprApplies is FALSE.", - requestHooks: [ - networkLogger.setConsentEndpointLogs, - networkLogger.edgeEndpointLogs, - ], -}); - -test.meta({ - ID: "C224673", - SEVERITY: "P0", - TEST_RUN: "REGRESSION", -}); - -test("Test C224673: Opt in to IAB while gdprApplies is FALSE", async () => { - const alloy = createAlloyProxy(); - await alloy.configure(config); - await alloy.setConsent(IAB_CONSENT_IN_NO_GDPR); - - await t.expect(networkLogger.setConsentEndpointLogs.requests.length).eql(1); - await responseStatus(networkLogger.edgeEndpointLogs.requests, [200, 207]); - - const consentRawResponse = JSON.parse( - getResponseBody(networkLogger.setConsentEndpointLogs.requests[0]), - ); - - const consentResponse = createResponse({ content: consentRawResponse }); - - // 1. The set-consent response should contain the Consent cookie: { general: in } - const consentCookieValue = await cookies.get(MAIN_CONSENT_COOKIE_NAME); - - await t.expect(consentCookieValue).ok("No consent cookie found."); - await t.expect(consentCookieValue).eql("general=in"); - - // 2. The ECID should exist in the response payload as well, if queried - const identityHandle = consentResponse.getPayloadsByType("identity:result"); - const returnedNamespaces = identityHandle.map((i) => i.namespace.code); - await t.expect(returnedNamespaces).contains("ECID"); - - await alloy.sendEvent(); - await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(1); -}); diff --git a/packages/core/test/functional/specs/Consent/IAB/C224674.js b/packages/core/test/functional/specs/Consent/IAB/C224674.js deleted file mode 100644 index 61a5bde00..000000000 --- a/packages/core/test/functional/specs/Consent/IAB/C224674.js +++ /dev/null @@ -1,74 +0,0 @@ -/* -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 } from "testcafe"; -import createNetworkLogger from "../../../helpers/networkLogger/index.js"; -import { responseStatus } from "../../../helpers/assertions/index.js"; -import createFixture from "../../../helpers/createFixture/index.js"; -import createResponse from "../../../helpers/createResponse.js"; -import getResponseBody from "../../../helpers/networkLogger/getResponseBody.js"; -import cookies from "../../../helpers/cookies.js"; -import { - compose, - orgMainConfigMain, - consentPending, - debugEnabled, -} from "../../../helpers/constants/configParts/index.js"; -import { MAIN_CONSENT_COOKIE_NAME } from "../../../helpers/constants/cookies.js"; -import createAlloyProxy from "../../../helpers/createAlloyProxy.js"; -import { IAB_NO_PURPOSE_ONE_NO_GRPR } from "../../../helpers/constants/consent.js"; - -const config = compose(orgMainConfigMain, consentPending, debugEnabled); - -const networkLogger = createNetworkLogger(); - -createFixture({ - title: "C224674: Opt out to IAB while gdprApplies is FALSE.", - requestHooks: [ - networkLogger.setConsentEndpointLogs, - networkLogger.edgeEndpointLogs, - ], -}); - -test.meta({ - ID: "C224674", - SEVERITY: "P0", - TEST_RUN: "REGRESSION", -}); - -test("Test C224674: Opt out to IAB while gdprApplies is FALSE", async () => { - const alloy = createAlloyProxy(); - await alloy.configure(config); - await alloy.setConsent(IAB_NO_PURPOSE_ONE_NO_GRPR); - - await t.expect(networkLogger.setConsentEndpointLogs.requests.length).eql(1); - await responseStatus(networkLogger.edgeEndpointLogs.requests, [200, 207]); - - const consentRawResponse = JSON.parse( - getResponseBody(networkLogger.setConsentEndpointLogs.requests[0]), - ); - - const consentResponse = createResponse({ content: consentRawResponse }); - - // 1. The set-consent response should contain the Consent cookie: { general: in } - const consentCookieValue = await cookies.get(MAIN_CONSENT_COOKIE_NAME); - - await t.expect(consentCookieValue).ok("No consent cookie found."); - await t.expect(consentCookieValue).eql("general=in"); - - // 2. The ECID should exist in the response payload as well, if queried - const identityHandle = consentResponse.getPayloadsByType("identity:result"); - const returnedNamespaces = identityHandle.map((i) => i.namespace.code); - await t.expect(returnedNamespaces).contains("ECID"); - - await alloy.sendEvent(); - await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(1); -}); diff --git a/packages/core/test/functional/specs/Consent/IAB/C224675.js b/packages/core/test/functional/specs/Consent/IAB/C224675.js deleted file mode 100644 index 67aa4924e..000000000 --- a/packages/core/test/functional/specs/Consent/IAB/C224675.js +++ /dev/null @@ -1,124 +0,0 @@ -/* -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 } from "testcafe"; -import createNetworkLogger from "../../../helpers/networkLogger/index.js"; -import createFixture from "../../../helpers/createFixture/index.js"; -import { - compose, - orgMainConfigMain, - consentPending, - debugEnabled, -} from "../../../helpers/constants/configParts/index.js"; -import createAlloyProxy from "../../../helpers/createAlloyProxy.js"; - -const config = compose(orgMainConfigMain, consentPending, debugEnabled); - -const networkLogger = createNetworkLogger(); - -createFixture({ - title: - "C224675: Passing invalid consent options should throw a validation error.", - requestHooks: [ - networkLogger.setConsentEndpointLogs, - networkLogger.edgeEndpointLogs, - ], -}); - -test.meta({ - ID: "C224675", - SEVERITY: "P0", - TEST_RUN: "REGRESSION", -}); - -test("Test C224675: Passing invalid consent options should throw a validation error", async () => { - const alloy = createAlloyProxy(); - await alloy.configure(config); - - const errorMessageForInvalidStandard = await alloy.setConsentErrorMessage({ - consent: [ - { - standard: "IAB", - version: "2.0", - value: "CO052l-O052l-DGAMBFRACBgAIBAAAAAAIYgEawAQEagAAAA", - }, - ], - }); - - await t - .expect(errorMessageForInvalidStandard) - .ok("Expected the setConsent command to be rejected"); - - await t - .expect(errorMessageForInvalidStandard) - .contains("The server responded with a status code 400") - .expect(errorMessageForInvalidStandard) - .contains("EXEG-0102-400"); - - const errorMessageForInvalidVersion = await alloy.setConsentErrorMessage({ - consent: [ - { - standard: "IAB TCF", - version: "6.9", - value: "CO052l-O052l-DGAMBFRACBgAIBAAAAAAIYgEawAQEagAAAA", - }, - ], - }); - - await t - .expect(errorMessageForInvalidVersion) - .ok("Expected the setConsent command to be rejected"); - - await t - .expect(errorMessageForInvalidVersion) - .contains("The server responded with a status code 400") - .expect(errorMessageForInvalidVersion) - .contains("EXEG-0102-400"); - - const errorMessageForInvalidValue = await alloy.setConsentErrorMessage({ - consent: [ - { - standard: "IAB TCF", - version: "2.0", - }, - ], - }); - - await t - .expect(errorMessageForInvalidValue) - .ok("Expected the setConsent command to be rejected"); - - await t - .expect(errorMessageForInvalidValue) - .contains("The server responded with a status code 400") - .expect(errorMessageForInvalidValue) - .contains("EXEG-0103-400"); - - const errorMessageForEmptyValue = await alloy.setConsentErrorMessage({ - consent: [ - { - standard: "IAB TCF", - version: "2.0", - value: "", - }, - ], - }); - - await t - .expect(errorMessageForEmptyValue) - .ok("Expected the setConsent command to be rejected"); - - await t - .expect(errorMessageForEmptyValue) - .contains("The server responded with a status code 422") - .expect(errorMessageForEmptyValue) - .contains("EXEG-0104-422"); -}); diff --git a/packages/core/test/functional/specs/Consent/IAB/C224676.js b/packages/core/test/functional/specs/Consent/IAB/C224676.js deleted file mode 100644 index b3681d5fe..000000000 --- a/packages/core/test/functional/specs/Consent/IAB/C224676.js +++ /dev/null @@ -1,83 +0,0 @@ -/* -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 } from "testcafe"; -import createNetworkLogger from "../../../helpers/networkLogger/index.js"; -import { responseStatus } from "../../../helpers/assertions/index.js"; -import createFixture from "../../../helpers/createFixture/index.js"; -import createResponse from "../../../helpers/createResponse.js"; -import getResponseBody from "../../../helpers/networkLogger/getResponseBody.js"; -import cookies from "../../../helpers/cookies.js"; -import { - compose, - orgMainConfigMain, - debugEnabled, -} from "../../../helpers/constants/configParts/index.js"; -import { MAIN_CONSENT_COOKIE_NAME } from "../../../helpers/constants/cookies.js"; -import createAlloyProxy from "../../../helpers/createAlloyProxy.js"; - -const config = compose(orgMainConfigMain, debugEnabled); - -const networkLogger = createNetworkLogger(); - -createFixture({ - title: "C224676: Passing a positive Consent in the sendEvent command.", - requestHooks: [networkLogger.edgeEndpointLogs], -}); - -test.meta({ - ID: "C224676", - SEVERITY: "P0", - TEST_RUN: "REGRESSION", -}); - -const eventOptionsWithConsent = { - xdm: { - consentStrings: [ - { - consentStandard: "IAB TCF", - consentStandardVersion: "2.0", - consentStringValue: "CO052l-O052l-DGAMBFRACBgAIBAAAAAAIYgEawAQEagAAAA", - gdprApplies: true, - containsPersonalData: false, - }, - ], - }, -}; - -test("Test C224676: Passing a positive Consent in the sendEvent command", async () => { - const alloy = createAlloyProxy(); - await alloy.configure(config); - await alloy.sendEvent(eventOptionsWithConsent); - - await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(1); - await responseStatus(networkLogger.edgeEndpointLogs.requests, [200, 207]); - - const rawResponse = JSON.parse( - getResponseBody(networkLogger.edgeEndpointLogs.requests[0]), - ); - - const response = createResponse({ content: rawResponse }); - - // 1. The set-consent response should contain the Consent cookie: { general: in } - const consentCookieValue = await cookies.get(MAIN_CONSENT_COOKIE_NAME); - - await t.expect(consentCookieValue).ok("No consent cookie found."); - await t.expect(consentCookieValue).eql("general=in"); - - // 2. The ECID should exist in the response payload as well, if queried - const identityHandle = response.getPayloadsByType("identity:result"); - const returnedNamespaces = identityHandle.map((i) => i.namespace.code); - await t.expect(returnedNamespaces).contains("ECID"); - - await alloy.sendEvent(); - await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(2); -}); diff --git a/packages/core/test/functional/specs/Consent/IAB/C224677.js b/packages/core/test/functional/specs/Consent/IAB/C224677.js deleted file mode 100644 index 735d464e6..000000000 --- a/packages/core/test/functional/specs/Consent/IAB/C224677.js +++ /dev/null @@ -1,91 +0,0 @@ -/* -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 } from "testcafe"; -import createNetworkLogger from "../../../helpers/networkLogger/index.js"; -import createFixture from "../../../helpers/createFixture/index.js"; -import createResponse from "../../../helpers/createResponse.js"; -import getResponseBody from "../../../helpers/networkLogger/getResponseBody.js"; -import cookies from "../../../helpers/cookies.js"; -import { - compose, - orgMainConfigMain, - debugEnabled, -} from "../../../helpers/constants/configParts/index.js"; -import { MAIN_CONSENT_COOKIE_NAME } from "../../../helpers/constants/cookies.js"; -import createAlloyProxy from "../../../helpers/createAlloyProxy.js"; -import { IAB_NO_PURPOSE_TEN } from "../../../helpers/constants/consent.js"; - -const config = compose(orgMainConfigMain, debugEnabled); - -const networkLogger = createNetworkLogger(); - -createFixture({ - title: "C224677: Call setConsent when purpose 10 is FALSE.", - requestHooks: [ - networkLogger.setConsentEndpointLogs, - networkLogger.edgeEndpointLogs, - ], -}); - -test.meta({ - ID: "C224677", - SEVERITY: "P0", - TEST_RUN: "REGRESSION", -}); - -test("Test C224677: Call setConsent when purpose 10 is FALSE", async () => { - const alloy = createAlloyProxy(); - await alloy.configure(config); - await alloy.setConsent(IAB_NO_PURPOSE_TEN); - - await t.expect(networkLogger.setConsentEndpointLogs.requests.length).eql(1); - - const rawResponse = JSON.parse( - getResponseBody(networkLogger.setConsentEndpointLogs.requests[0]), - ); - - const response = createResponse({ content: rawResponse }); - - // 1. The set-consent response should contain the Consent cookie: { general: in } - const consentCookieValue = await cookies.get(MAIN_CONSENT_COOKIE_NAME); - - await t.expect(consentCookieValue).ok("No consent cookie found."); - await t.expect(consentCookieValue).eql("general=in"); - - // 2. The ECID should exist in the response payload as well, if queried - const identityHandle = response.getPayloadsByType("identity:result"); - const returnedNamespaces = identityHandle.map((i) => i.namespace.code); - await t.expect(returnedNamespaces).contains("ECID"); - - // 3. Event calls going forward should remain opted in, even though AAM opts out consents with no purpose 10. - await alloy.sendEvent(); - const rawEventResponse = JSON.parse( - getResponseBody(networkLogger.edgeEndpointLogs.requests[0]), - ); - const eventResponse = createResponse({ content: rawEventResponse }); - - // 4. No warning message regarding opt-out should be returned anymore - const warningTypes = eventResponse.getWarnings().map((w) => w.type); - await t - .expect(warningTypes) - .notContains("https://ns.adobe.com/aep/errors/EXEG-0301-200"); - - await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(1); - await t - .expect( - networkLogger.edgeEndpointLogs.count( - ({ response: { statusCode } }) => - statusCode === 200 || statusCode === 207, - ), - ) - .eql(1); -}); diff --git a/packages/core/test/functional/specs/Consent/IAB/C224678.js b/packages/core/test/functional/specs/Consent/IAB/C224678.js deleted file mode 100644 index 0ae00d37d..000000000 --- a/packages/core/test/functional/specs/Consent/IAB/C224678.js +++ /dev/null @@ -1,111 +0,0 @@ -/* -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 } from "testcafe"; -import createNetworkLogger from "../../../helpers/networkLogger/index.js"; -import { responseStatus } from "../../../helpers/assertions/index.js"; -import createFixture from "../../../helpers/createFixture/index.js"; -import createResponse from "../../../helpers/createResponse.js"; -import getResponseBody from "../../../helpers/networkLogger/getResponseBody.js"; -import cookies from "../../../helpers/cookies.js"; -import { - compose, - orgMainConfigMain, - debugEnabled, -} from "../../../helpers/constants/configParts/index.js"; -import { MAIN_CONSENT_COOKIE_NAME } from "../../../helpers/constants/cookies.js"; -import createAlloyProxy from "../../../helpers/createAlloyProxy.js"; - -const config = compose(orgMainConfigMain, debugEnabled); - -const networkLogger = createNetworkLogger(); - -createFixture({ - title: "C224678: Passing a negative Consent in the sendEvent command.", - requestHooks: [networkLogger.edgeEndpointLogs], -}); - -test.meta({ - ID: "C224678", - SEVERITY: "P0", - TEST_RUN: "REGRESSION", -}); - -// Consent with no Purpose 1, should result in Opt-Out. -const sendEventOptions = { - xdm: { - consentStrings: [ - { - consentStandard: "IAB TCF", - consentStandardVersion: "2.0", - consentStringValue: "CO052oTO052oTDGAMBFRACBgAABAAAAAAIYgEawAQEagAAAA", - gdprApplies: true, - containsPersonalData: false, - }, - ], - }, -}; - -test("Test C224678: Passing a negative Consent in the sendEvent command", async () => { - const alloy = createAlloyProxy(); - await alloy.configure(config); - const errorMessage = await alloy.sendEventErrorMessage(sendEventOptions); - - await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(1); - await responseStatus(networkLogger.edgeEndpointLogs.requests, [200, 207]); - - const rawResponse = JSON.parse( - getResponseBody(networkLogger.edgeEndpointLogs.requests[0]), - ); - - const response = createResponse({ content: rawResponse }); - - // 1. The set-consent response should contain the Consent cookie: { general: out } - const consentCookieValue = await cookies.get(MAIN_CONSENT_COOKIE_NAME); - - await t.expect(consentCookieValue).ok("No consent cookie found."); - await t.expect(consentCookieValue).eql("general=out"); - - // 2. The ECID should exist in the response payload as well, even if queried - const identityHandle = response.getPayloadsByType("identity:result"); - const returnedNamespaces = identityHandle.map((i) => i.namespace.code); - await t.expect(returnedNamespaces).contains("ECID"); - - // 3. Should not have any activation, ID Syncs or decisions in the response. - const handlesThatShouldBeMissing = [ - "activation:push", - "identity:exchange", - "personalization:decisions", - ].reduce((handles, handleType) => { - const handle = response.getPayloadsByType(handleType); - if (handle.length) { - handles.push(handle); - } - return handles; - }, []); - - await t.expect(handlesThatShouldBeMissing.length).eql(0); - - // 4. The server doesn't throw error messages when there is no consent - await t - .expect(errorMessage) - .notOk("Event returned an error when we expected it not to."); - - // 5. But returns a warning message confirming the opt-out - const warningTypes = response.getWarnings().map((w) => w.type); - await t - .expect(warningTypes) - .contains("https://ns.adobe.com/aep/errors/EXEG-0301-200"); - - // 6. Events should be blocked going forward because we are opted out. - await alloy.sendEvent(); - await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(1); -}); diff --git a/packages/core/test/functional/specs/Context/C1911390.js b/packages/core/test/functional/specs/Context/C1911390.js deleted file mode 100644 index 4f2f3bd2a..000000000 --- a/packages/core/test/functional/specs/Context/C1911390.js +++ /dev/null @@ -1,104 +0,0 @@ -/* -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 } from "testcafe"; -import createNetworkLogger from "../../helpers/networkLogger/index.js"; -import createFixture from "../../helpers/createFixture/index.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; -import { orgMainConfigMain } from "../../helpers/constants/configParts/index.js"; - -const networkLogger = createNetworkLogger(); - -const ID = "C1911390"; -const DESCRIPTION = `${ID} - Ensure user-provided fields for context data don't leak across requests.`; - -createFixture({ - title: DESCRIPTION, - requestHooks: [networkLogger.edgeEndpointLogs], -}); - -test.meta({ - ID, - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -test(DESCRIPTION, async () => { - const alloy = createAlloyProxy(); - await alloy.configure(orgMainConfigMain); - await alloy.sendEvent({ - xdm: { - device: { - customDeviceField: "foo", - }, - environment: { - customEnvironmentField: "foo", - }, - implementationDetails: { - customImplementationDetailsField: "foo", - }, - placeContext: { - customPlaceContextField: "foo", - }, - web: { - customWebField: "foo", - }, - }, - }); - - await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(1); - - let parsedBody = JSON.parse( - networkLogger.edgeEndpointLogs.requests[0].request.body, - ); - let sentXdm = parsedBody.events[0].xdm; - - await t - .expect(sentXdm.device.customDeviceField) - .eql("foo", "custom device field incorrectly populated"); - await t - .expect(sentXdm.environment.customEnvironmentField) - .eql("foo", "custom environment field incorrectly populated"); - await t - .expect(sentXdm.implementationDetails.customImplementationDetailsField) - .eql("foo", "custom implementation details field incorrectly populated"); - await t - .expect(sentXdm.placeContext.customPlaceContextField) - .eql("foo", "custom place context field incorrectly populated"); - await t - .expect(sentXdm.web.customWebField) - .eql("foo", "custom web field incorrectly populated"); - - await alloy.sendEvent({}); - - await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(2); - - parsedBody = JSON.parse( - networkLogger.edgeEndpointLogs.requests[1].request.body, - ); - sentXdm = parsedBody.events[0].xdm; - - await t - .expect(sentXdm.device.customDeviceField) - .notOk("custom device field should be undefined"); - await t - .expect(sentXdm.environment.customEnvironmentField) - .notOk("custom environment field should be undefined"); - await t - .expect(sentXdm.implementationDetails.customImplementationDetailsField) - .notOk("custom implementation details field should be undefined"); - await t - .expect(sentXdm.placeContext.customPlaceContextField) - .notOk("custom place context field should be undefined"); - await t - .expect(sentXdm.web.customWebField) - .notOk("custom web field should be undefined"); -}); diff --git a/packages/core/test/functional/specs/Context/C2597.js b/packages/core/test/functional/specs/Context/C2597.js deleted file mode 100644 index f950c6bb4..000000000 --- a/packages/core/test/functional/specs/Context/C2597.js +++ /dev/null @@ -1,60 +0,0 @@ -/* -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 } from "testcafe"; -import createNetworkLogger from "../../helpers/networkLogger/index.js"; -import { responseStatus } from "../../helpers/assertions/index.js"; -import createFixture from "../../helpers/createFixture/index.js"; -import { orgMainConfigMain } from "../../helpers/constants/configParts/index.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; -import isUserAgentClientHintsSupported from "../../helpers/isUserAgentClientHintsSupported.js"; - -const networkLogger = createNetworkLogger(); - -const ID = "C2597"; -const DESCRIPTION = `${ID} - Adds all context data to requests by default.`; - -createFixture({ - title: DESCRIPTION, - requestHooks: [networkLogger.edgeEndpointLogs], -}); - -test.meta({ - ID, - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -test(DESCRIPTION, async () => { - const alloy = createAlloyProxy(); - await alloy.configure(orgMainConfigMain); - await alloy.sendEvent(); - - await responseStatus(networkLogger.edgeEndpointLogs.requests, [200, 207]); - await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(1); - - const parsedBody = JSON.parse( - networkLogger.edgeEndpointLogs.requests[0].request.body, - ); - - await t.expect(parsedBody.events[0].xdm.device).ok(); - await t.expect(parsedBody.events[0].xdm.placeContext).ok(); - await t.expect(parsedBody.events[0].xdm.environment.type).ok(); - await t.expect(parsedBody.events[0].xdm.web.webPageDetails).ok(); - if (await isUserAgentClientHintsSupported()) { - await t - .expect( - parsedBody.events[0].xdm?.environment?.browserDetails - ?.userAgentClientHints, - ) - .notOk(); - } -}); diff --git a/packages/core/test/functional/specs/Context/C2598.js b/packages/core/test/functional/specs/Context/C2598.js deleted file mode 100644 index 6b53c5f29..000000000 --- a/packages/core/test/functional/specs/Context/C2598.js +++ /dev/null @@ -1,77 +0,0 @@ -/* -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 } from "testcafe"; -import createNetworkLogger from "../../helpers/networkLogger/index.js"; -import { responseStatus } from "../../helpers/assertions/index.js"; -import createFixture from "../../helpers/createFixture/index.js"; -import webContextConfig from "../../helpers/constants/webContextConfig.js"; -import { TEST_PAGE as TEST_PAGE_URL } from "../../helpers/constants/url.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; -import isUserAgentClientHintsSupported from "../../helpers/isUserAgentClientHintsSupported.js"; - -const networkLogger = createNetworkLogger(); - -const ID = "C2598"; -const DESCRIPTION = `${ID} - Adds only web context data when only web is specified in configuration.`; - -createFixture({ - title: DESCRIPTION, - requestHooks: [networkLogger.edgeEndpointLogs], - url: TEST_PAGE_URL, -}); - -test.meta({ - ID, - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -test(DESCRIPTION, async () => { - // navigate to set the document.referrer - await t.eval(() => { - window.document.location = `${window.document.location}`; - }); - - const alloy = createAlloyProxy(); - await alloy.configure(webContextConfig); - await alloy.sendEvent(); - - await responseStatus(networkLogger.edgeEndpointLogs.requests, [200, 207]); - await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(1); - - const parsedBody = JSON.parse( - networkLogger.edgeEndpointLogs.requests[0].request.body, - ); - - await t.expect(parsedBody.events[0].xdm.web).ok(); - await t.expect(parsedBody.events[0].xdm.web.webPageDetails).ok(); - await t - .expect(parsedBody.events[0].xdm.web.webPageDetails.URL) - .eql(TEST_PAGE_URL); - await t.expect(parsedBody.events[0].xdm.web.webReferrer).ok(); - await t - .expect(parsedBody.events[0].xdm.web.webReferrer.URL) - .eql(TEST_PAGE_URL); - - await t.expect(parsedBody.events[0].xdm.device).notOk(); - await t.expect(parsedBody.events[0].xdm.placeContext).notOk(); - await t.expect(parsedBody.events[0].xdm.environment).notOk(); - - if (await isUserAgentClientHintsSupported()) { - await t - .expect( - parsedBody.events[0].xdm?.environment?.browserDetails - ?.userAgentClientHints, - ) - .notOk(); - } -}); diff --git a/packages/core/test/functional/specs/Context/C2599.js b/packages/core/test/functional/specs/Context/C2599.js deleted file mode 100644 index 5e1c1c43d..000000000 --- a/packages/core/test/functional/specs/Context/C2599.js +++ /dev/null @@ -1,71 +0,0 @@ -/* -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 } from "testcafe"; -import createNetworkLogger from "../../helpers/networkLogger/index.js"; -import { responseStatus } from "../../helpers/assertions/index.js"; -import createFixture from "../../helpers/createFixture/index.js"; -import deviceContextConfig from "../../helpers/constants/deviceContextConfig.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; -import { TEST_PAGE as TEST_PAGE_URL } from "../../helpers/constants/url.js"; -import isUserAgentClientHintsSupported from "../../helpers/isUserAgentClientHintsSupported.js"; - -const networkLogger = createNetworkLogger(); - -const ID = "C2599"; -const DESCRIPTION = `${ID} - Adds only device context data when only device is specified in configuration.`; - -createFixture({ - title: DESCRIPTION, - requestHooks: [networkLogger.edgeEndpointLogs], -}); - -test.meta({ - ID, - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -const sendEventOptions = { - xdm: { - web: { - webPageDetails: { - URL: TEST_PAGE_URL, - }, - }, - }, -}; - -test(DESCRIPTION, async () => { - const alloy = createAlloyProxy(); - await alloy.configure(deviceContextConfig); - await alloy.sendEvent(sendEventOptions); - - await responseStatus(networkLogger.edgeEndpointLogs.requests, [200, 207]); - await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(1); - - const parsedBody = JSON.parse( - networkLogger.edgeEndpointLogs.requests[0].request.body, - ); - - await t.expect(parsedBody.events[0].xdm.device).ok(); - await t.expect(parsedBody.events[0].xdm.web.webPageDetails).ok(); - await t.expect(parsedBody.events[0].xdm.placeContext).notOk(); - await t.expect(parsedBody.events[0].xdm.environment).notOk(); - if (await isUserAgentClientHintsSupported()) { - await t - .expect( - parsedBody.events[0].xdm?.environment?.browserDetails - ?.userAgentClientHints, - ) - .notOk(); - } -}); diff --git a/packages/core/test/functional/specs/Context/C2600.js b/packages/core/test/functional/specs/Context/C2600.js deleted file mode 100644 index 14b45bf16..000000000 --- a/packages/core/test/functional/specs/Context/C2600.js +++ /dev/null @@ -1,71 +0,0 @@ -/* -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 } from "testcafe"; -import createNetworkLogger from "../../helpers/networkLogger/index.js"; -import { responseStatus } from "../../helpers/assertions/index.js"; -import createFixture from "../../helpers/createFixture/index.js"; -import environmentContextConfig from "../../helpers/constants/environmentContextConfig.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; -import { TEST_PAGE as TEST_PAGE_URL } from "../../helpers/constants/url.js"; -import isUserAgentClientHintsSupported from "../../helpers/isUserAgentClientHintsSupported.js"; - -const networkLogger = createNetworkLogger(); - -const ID = "C2600"; -const DESCRIPTION = `${ID} - Adds only environment context data when only device is specified in configuration.`; - -createFixture({ - title: DESCRIPTION, - requestHooks: [networkLogger.edgeEndpointLogs], -}); - -test.meta({ - ID, - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -const sendEventOptions = { - xdm: { - web: { - webPageDetails: { - URL: TEST_PAGE_URL, - }, - }, - }, -}; - -test(DESCRIPTION, async () => { - const alloy = createAlloyProxy(); - await alloy.configure(environmentContextConfig); - await alloy.sendEvent(sendEventOptions); - - await responseStatus(networkLogger.edgeEndpointLogs.requests, [200, 207]); - await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(1); - - const parsedBody = JSON.parse( - networkLogger.edgeEndpointLogs.requests[0].request.body, - ); - - await t.expect(parsedBody.events[0].xdm.environment).ok(); - await t.expect(parsedBody.events[0].xdm.web.webPageDetails).ok(); - await t.expect(parsedBody.events[0].xdm.device).notOk(); - await t.expect(parsedBody.events[0].xdm.placeContext).notOk(); - if (await isUserAgentClientHintsSupported()) { - await t - .expect( - parsedBody.events[0].xdm?.environment?.browserDetails - ?.userAgentClientHints, - ) - .notOk(); - } -}); diff --git a/packages/core/test/functional/specs/Context/C2601.js b/packages/core/test/functional/specs/Context/C2601.js deleted file mode 100644 index 5c98f9c90..000000000 --- a/packages/core/test/functional/specs/Context/C2601.js +++ /dev/null @@ -1,71 +0,0 @@ -/* -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 } from "testcafe"; -import createNetworkLogger from "../../helpers/networkLogger/index.js"; -import { responseStatus } from "../../helpers/assertions/index.js"; -import createFixture from "../../helpers/createFixture/index.js"; -import placeContextConfig from "../../helpers/constants/placeContextConfig.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; -import { TEST_PAGE as TEST_PAGE_URL } from "../../helpers/constants/url.js"; -import isUserAgentClientHintsSupported from "../../helpers/isUserAgentClientHintsSupported.js"; - -const networkLogger = createNetworkLogger(); - -const ID = "C2601"; -const DESCRIPTION = `${ID} - Adds only placeContext context data when only device is specified in configuration.`; - -createFixture({ - title: DESCRIPTION, - requestHooks: [networkLogger.edgeEndpointLogs], -}); - -test.meta({ - ID, - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -const sendEventOptions = { - xdm: { - web: { - webPageDetails: { - URL: TEST_PAGE_URL, - }, - }, - }, -}; - -test(DESCRIPTION, async () => { - const alloy = createAlloyProxy(); - await alloy.configure(placeContextConfig); - await alloy.sendEvent(sendEventOptions); - - await responseStatus(networkLogger.edgeEndpointLogs.requests, [200, 207]); - await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(1); - - const parsedBody = JSON.parse( - networkLogger.edgeEndpointLogs.requests[0].request.body, - ); - - await t.expect(parsedBody.events[0].xdm.placeContext).ok(); - await t.expect(parsedBody.events[0].xdm.web.webPageDetails).ok(); - await t.expect(parsedBody.events[0].xdm.environment).notOk(); - await t.expect(parsedBody.events[0].xdm.device).notOk(); - if (await isUserAgentClientHintsSupported()) { - await t - .expect( - parsedBody.events[0].xdm?.environment?.browserDetails - ?.userAgentClientHints, - ) - .notOk(); - } -}); diff --git a/packages/core/test/functional/specs/Context/C7311732.js b/packages/core/test/functional/specs/Context/C7311732.js deleted file mode 100644 index 29567a814..000000000 --- a/packages/core/test/functional/specs/Context/C7311732.js +++ /dev/null @@ -1,71 +0,0 @@ -/* -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 } from "testcafe"; -import createNetworkLogger from "../../helpers/networkLogger/index.js"; -import { responseStatus } from "../../helpers/assertions/index.js"; -import createFixture from "../../helpers/createFixture/index.js"; -import highEntropyUserAgentHintsContextConfig from "../../helpers/constants/highEntropyUserAgentHintsContextConfig.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; -import { TEST_PAGE as TEST_PAGE_URL } from "../../helpers/constants/url.js"; -import isUserAgentClientHintsSupported from "../../helpers/isUserAgentClientHintsSupported.js"; - -const networkLogger = createNetworkLogger(); - -const ID = "C7311732"; -const DESCRIPTION = `${ID} - Adds only userAgentClientHints context data when only highEntropyUserAgentHints is specified in configuration.`; - -createFixture({ - title: DESCRIPTION, - requestHooks: [networkLogger.edgeEndpointLogs], -}); - -test.meta({ - ID, - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -const sendEventOptions = { - xdm: { - web: { - webPageDetails: { - URL: TEST_PAGE_URL, - }, - }, - }, -}; - -test(DESCRIPTION, async () => { - const alloy = createAlloyProxy(); - await alloy.configure(highEntropyUserAgentHintsContextConfig); - await alloy.sendEvent(sendEventOptions); - - await responseStatus(networkLogger.edgeEndpointLogs.requests, [200, 207]); - await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(1); - - const parsedBody = JSON.parse( - networkLogger.edgeEndpointLogs.requests[0].request.body, - ); - - await t.expect(parsedBody.events[0].xdm.placeContext).notOk(); - await t.expect(parsedBody.events[0].xdm.web.webPageDetails).ok(); - await t.expect(parsedBody.events[0].xdm.device).notOk(); - if (await isUserAgentClientHintsSupported()) { - await t.expect(parsedBody.events[0].xdm.environment.type).notOk(); - await t - .expect( - parsedBody.events[0].xdm.environment.browserDetails - .userAgentClientHints, - ) - .ok(); - } -}); diff --git a/packages/core/test/functional/specs/Data Collector/C11693274.js b/packages/core/test/functional/specs/Data Collector/C11693274.js deleted file mode 100644 index 961f205c2..000000000 --- a/packages/core/test/functional/specs/Data Collector/C11693274.js +++ /dev/null @@ -1,69 +0,0 @@ -/* -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, Selector } from "testcafe"; -import createFixture from "../../helpers/createFixture/index.js"; -import addHtmlToBody from "../../helpers/dom/addHtmlToBody.js"; -import { - compose, - orgMainConfigMain, - clickCollectionEnabled, -} from "../../helpers/constants/configParts/index.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; -import preventLinkNavigation from "../../helpers/preventLinkNavigation.js"; -import createCollectEndpointAsserter from "../../helpers/createCollectEndpointAsserter.js"; - -createFixture({ - title: "C11693274: Does not search query parameters to qualify exit links.", -}); - -test.meta({ - ID: "C11693274", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -const addLinkToBody = () => { - return addHtmlToBody( - `Test Link`, - ); -}; - -const clickLink = async () => { - await t.click(Selector("#alloy-link-test")); -}; - -const assertRequestXdm = async (request) => { - const requestBody = JSON.parse(request.request.body); - const eventXdm = requestBody.events[0].xdm; - await t.expect(eventXdm.eventType).eql("web.webinteraction.linkClicks"); - await t.expect(eventXdm.web.webInteraction).eql({ - name: "Test Link", - region: "BODY", - type: "exit", - URL: "https://example.com/?exclude-this=alloyio.com", - linkClicks: { value: 1 }, - }); -}; - -test("Test C11693274: Verify URL query does not affect determining exit link type", async () => { - const collectEndpointAsserter = await createCollectEndpointAsserter(); - await preventLinkNavigation(); - const alloy = createAlloyProxy(); - const testConfig = compose(orgMainConfigMain, clickCollectionEnabled); - await alloy.configure(testConfig); - await addLinkToBody(); - await clickLink(); - await collectEndpointAsserter.assertInteractCalledAndNotCollect(); - const interactRequest = await collectEndpointAsserter.getInteractRequest(); - await collectEndpointAsserter.reset(); - await assertRequestXdm(interactRequest); -}); diff --git a/packages/core/test/functional/specs/Data Collector/C1715149.js b/packages/core/test/functional/specs/Data Collector/C1715149.js deleted file mode 100644 index c46488f16..000000000 --- a/packages/core/test/functional/specs/Data Collector/C1715149.js +++ /dev/null @@ -1,100 +0,0 @@ -/* -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 createNetworkLogger from "../../helpers/networkLogger/index.js"; -import createFixture from "../../helpers/createFixture/index.js"; -import { - debugEnabled, - orgMainConfigMain, -} from "../../helpers/constants/configParts/index.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; -import createConsoleLogger from "../../helpers/consoleLogger/index.js"; - -const networkLogger = createNetworkLogger(); - -const onBeforeEventSend = ClientFunction((content) => { - window.onBeforeEventSendCalled = true; - content.xdm.foo = "bar"; -}); - -const onBeforeEventSendFailed = ClientFunction(() => { - window.onBeforeEventSendCalled = true; - throw new Error("Expected Error"); -}); - -const onBeforeEventSendFalse = ClientFunction(() => { - window.onBeforeEventSendCalled = true; - return false; -}); - -const getOnBeforeEventSendCalled = ClientFunction(() => { - return window.onBeforeEventSendCalled === true; -}); - -createFixture({ - title: - "C1715149 sendEvent should call onBeforeEventSend callback and send when expected", - requestHooks: [networkLogger.edgeInteractEndpointLogs], -}); - -test.meta({ - ID: "C1715149", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -test("C1715149 Events should call onBeforeEventSend callback and still send event", async () => { - const alloy = createAlloyProxy(); - await alloy.configure({ - ...orgMainConfigMain, - onBeforeEventSend, - }); - await alloy.sendEvent(); - - await t.expect(getOnBeforeEventSendCalled()).eql(true); - const request = - networkLogger.edgeInteractEndpointLogs.requests[0].request.body; - const parsedRequest = JSON.parse(request); - await t.expect(parsedRequest.events[0].xdm.foo).eql("bar"); -}); - -test("C1715149 Events should call onBeforeEventSend callback, fail, and not send event", async () => { - const alloy = createAlloyProxy(); - await alloy.configure({ - ...orgMainConfigMain, - onBeforeEventSend: onBeforeEventSendFailed, - }); - const errorMessage = await alloy.sendEventErrorMessage(); - - await t.expect(getOnBeforeEventSendCalled()).eql(true); - await t.expect(errorMessage).match(/Expected Error/); - await t.expect(networkLogger.edgeInteractEndpointLogs.requests.length).eql(0); -}); - -test("C1715149 Events should call onBeforeEventSend callback, return false, and not send event", async () => { - const logger = await createConsoleLogger(); - const alloy = createAlloyProxy(); - await alloy.configure({ - ...orgMainConfigMain, - ...debugEnabled, - onBeforeEventSend: onBeforeEventSendFalse, - }); - - const result = await alloy.sendEvent(); - - await t.expect(getOnBeforeEventSendCalled()).eql(true); - - // if event is cancelled, the promise should resolve with an empty object - await t.expect(result).eql({}); - await t.expect(networkLogger.edgeInteractEndpointLogs.requests.length).eql(0); - await logger.info.expectMessageMatching(/Event was canceled/); -}); diff --git a/packages/core/test/functional/specs/Data Collector/C225010.js b/packages/core/test/functional/specs/Data Collector/C225010.js deleted file mode 100644 index 9a950221f..000000000 --- a/packages/core/test/functional/specs/Data Collector/C225010.js +++ /dev/null @@ -1,61 +0,0 @@ -/* -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, Selector, ClientFunction } from "testcafe"; -import createFixture from "../../helpers/createFixture/index.js"; -import addHtmlToBody from "../../helpers/dom/addHtmlToBody.js"; -import createConsoleLogger from "../../helpers/consoleLogger/index.js"; -import createUnhandledRejectionLogger from "../../helpers/createUnhandledRejectionLogger.js"; -import { - compose, - orgMainConfigMain, - consentPending, - debugEnabled, - clickCollectionEnabled, - clickCollectionEventGroupingDisabled, -} from "../../helpers/constants/configParts/index.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; -import { CONSENT_OUT } from "../../helpers/constants/consent.js"; - -createFixture({ - title: "C225010: Click collection handles errors when user declines consent", -}); - -test.meta({ - ID: "C8118", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -test("Test C225010: Click collection handles errors when user declines consent", async () => { - const alloy = createAlloyProxy(); - const getLocation = ClientFunction(() => document.location.href.toString()); - const testConfig = compose( - orgMainConfigMain, - consentPending, - debugEnabled, - clickCollectionEnabled, - clickCollectionEventGroupingDisabled, - ); - await alloy.configure(testConfig); - await alloy.setConsent(CONSENT_OUT); - - await addHtmlToBody(`Test Link`); - - const consoleLogger = await createConsoleLogger(); - const unhandledRejectionLogger = await createUnhandledRejectionLogger(); - await t.click(Selector("#alloy-link-test")); - await t.expect(getLocation()).contains("#foo"); - await consoleLogger.warn.expectMessageMatching( - /The click collection could not fully complete. The user declined consent./, - ); - await unhandledRejectionLogger.expectNoMessageMatching(/.*/); -}); diff --git a/packages/core/test/functional/specs/Data Collector/C2592.js b/packages/core/test/functional/specs/Data Collector/C2592.js deleted file mode 100644 index 891bbdba8..000000000 --- a/packages/core/test/functional/specs/Data Collector/C2592.js +++ /dev/null @@ -1,63 +0,0 @@ -/* -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 } from "testcafe"; -import createNetworkLogger from "../../helpers/networkLogger/index.js"; -import { responseStatus } from "../../helpers/assertions/index.js"; -import createFixture from "../../helpers/createFixture/index.js"; -import { - compose, - configOverridesMain, - orgMainConfigMain, - debugEnabled, -} from "../../helpers/constants/configParts/index.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; - -const networkLogger = createNetworkLogger(); -const config = compose(orgMainConfigMain, debugEnabled); - -createFixture({ - title: "C2592: Event command sends a request", - requestHooks: [networkLogger.edgeEndpointLogs], -}); - -test.meta({ - ID: "C2592", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -test("Test C2592: Event command sends a request.", async () => { - const alloy = createAlloyProxy(); - await alloy.configure(config); - await alloy.sendEvent({ - datasetId: - configOverridesMain.com_adobe_experience_platform.datasets.event - .datasetId, - }); - - await responseStatus(networkLogger.edgeEndpointLogs.requests, [200, 207]); - - await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(1); - - const request = JSON.parse( - networkLogger.edgeEndpointLogs.requests[0].request.body, - ); - - await t - .expect(request.events[0].xdm.implementationDetails.name) - .eql("https://ns.adobe.com/experience/alloy"); - await t - .expect(request.meta.configOverrides.com_adobe_experience_platform.event) - .eql(configOverridesMain.com_adobe_experience_platform.event); - await t.expect(request.meta.state.cookiesEnabled).eql(true); - await t.expect(request.meta.state.domain).ok(); -}); diff --git a/packages/core/test/functional/specs/Data Collector/C455258.js b/packages/core/test/functional/specs/Data Collector/C455258.js deleted file mode 100644 index ef8646c56..000000000 --- a/packages/core/test/functional/specs/Data Collector/C455258.js +++ /dev/null @@ -1,49 +0,0 @@ -/* -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 createFixture from "../../helpers/createFixture/index.js"; -import { orgMainConfigMain } from "../../helpers/constants/configParts/index.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; -import createCollectEndpointAsserter from "../../helpers/createCollectEndpointAsserter.js"; - -createFixture({ - title: - "C455258: sendEvent command sends a request to the collect endpoint using sendBeacon when documentUnloading is set to true but only when identity has established.", -}); - -test.meta({ - ID: "C455258", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -test("Test C455258: sendEvent command sends a request to the collect endpoint when identity has been established and documentUnloading is set to true, interact otherwise.", async () => { - const collectEndpointAsserter = await createCollectEndpointAsserter(); - const alloy = createAlloyProxy(); - await alloy.configure(orgMainConfigMain); - - // An identity has not yet been established. This request should go to the - // interact endpoint. - await alloy.sendEvent({ documentUnloading: true }); - await collectEndpointAsserter.assertInteractCalledAndNotCollect(); - await collectEndpointAsserter.reset(); - - // An identity has been established. This request should go to the - // collect endpoint. - await alloy.sendEvent({ documentUnloading: true }); - await collectEndpointAsserter.assertCollectCalledAndNotInteract(); - await collectEndpointAsserter.reset(); - - // documentUnloading is not set to true. The request should go to the - // interact endpoint. - await alloy.sendEvent(); - await collectEndpointAsserter.assertInteractCalledAndNotCollect(); -}); diff --git a/packages/core/test/functional/specs/Data Collector/C75372.js b/packages/core/test/functional/specs/Data Collector/C75372.js deleted file mode 100644 index c891d8380..000000000 --- a/packages/core/test/functional/specs/Data Collector/C75372.js +++ /dev/null @@ -1,57 +0,0 @@ -/* -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 createNetworkLogger from "../../helpers/networkLogger/index.js"; -import createFixture from "../../helpers/createFixture/index.js"; -import { orgMainConfigMain } from "../../helpers/constants/configParts/index.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; - -const networkLogger = createNetworkLogger(); - -createFixture({ - title: - "C75372 - XDM and data objects passed into event command should not be modified", - requestHooks: [networkLogger.setConsentEndpointLogs], -}); - -test.meta({ - ID: "C75372", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -const sendEvent = ClientFunction(() => { - const xdmDataLayer = { device: { screenHeight: 1 } }; - const nonXdmDataLayer = { baz: "quux" }; - // Using a merge ID is a decent test because it's one thing we know - // gets merged with the XDM object. - return window - .alloy("sendEvent", { - xdm: xdmDataLayer, - data: nonXdmDataLayer, - mergeId: "abc", - }) - .then(() => { - return { - xdmDataLayer, - nonXdmDataLayer, - }; - }); -}); - -test("C75372 - XDM and data objects passed into event command should not be modified", async () => { - const alloy = createAlloyProxy(); - await alloy.configure(orgMainConfigMain); - const { xdmDataLayer, nonXdmDataLayer } = await sendEvent(); - await t.expect(xdmDataLayer).eql({ device: { screenHeight: 1 } }); - await t.expect(nonXdmDataLayer).eql({ baz: "quux" }); -}); diff --git a/packages/core/test/functional/specs/Data Collector/C8118.js b/packages/core/test/functional/specs/Data Collector/C8118.js deleted file mode 100644 index 9a22c8e54..000000000 --- a/packages/core/test/functional/specs/Data Collector/C8118.js +++ /dev/null @@ -1,503 +0,0 @@ -/* -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, Selector } from "testcafe"; -import createFixture from "../../helpers/createFixture/index.js"; -import addHtmlToBody from "../../helpers/dom/addHtmlToBody.js"; -import { - compose, - orgMainConfigMain, - clickCollectionEnabled, - clickCollectionEventGroupingDisabled, -} from "../../helpers/constants/configParts/index.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; -import preventLinkNavigation from "../../helpers/preventLinkNavigation.js"; -import createCollectEndpointAsserter from "../../helpers/createCollectEndpointAsserter.js"; - -createFixture({ - title: "C8118: Collects and sends information about link clicks.", -}); - -test.meta({ - ID: "C8118", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -const INTERNAL_LINK_ANCHOR_1 = `Test Link`; -const INTERNAL_LINK_ANCHOR_2 = `Internal Link`; -const DOWNLOAD_LINK_ANCHOR = `Download Zip File`; -const EXTERNAL_LINK_ANCHOR = `External Link`; - -const addLinkToBody = (link) => { - return addHtmlToBody(`${link}`); -}; - -const clickLink = async () => { - await t.click(Selector("#alloy-link-test")); -}; - -const getEventTypeFromRequest = (req) => { - const bodyJson = JSON.parse(req.request.body); - return bodyJson.events[0].xdm.eventType; -}; - -const getWebInteractionFromRequest = (req) => { - const bodyJson = JSON.parse(req.request.body); - return bodyJson.events[0].xdm.web.webInteraction; -}; - -const getXdmFromRequest = (req) => { - const bodyJson = JSON.parse(req.request.body); - return bodyJson.events[0].xdm; -}; - -/* eslint no-underscore-dangle: 0 */ -const getActivityMapDataFromRequest = (req) => { - const bodyJson = JSON.parse(req.request.body); - return bodyJson.events[0].data.__adobe.analytics.contextData.a.activitymap; -}; - -const assertRequestXdm = async (req) => { - const eventType = getEventTypeFromRequest(req); - await t.expect(eventType).eql("web.webinteraction.linkClicks"); - const webInteraction = getWebInteractionFromRequest(req); - await t.expect(webInteraction).eql({ - name: "Test Link", - region: "BODY", - type: "other", - URL: "https://alloyio.com/functional-test/blank.html", - linkClicks: { value: 1 }, - }); -}; - -test("Test C8118: Verify link click sends a request to the collect endpoint when identity has been established, interact endpoint otherwise", async () => { - const testConfig = compose( - orgMainConfigMain, - clickCollectionEnabled, - clickCollectionEventGroupingDisabled, // To prevent internal link click to get cached - ); - const collectEndpointAsserter = await createCollectEndpointAsserter(); - const alloy = createAlloyProxy(); - await alloy.configure(testConfig); - await preventLinkNavigation(); - await addLinkToBody(INTERNAL_LINK_ANCHOR_1); - await clickLink(); - await collectEndpointAsserter.assertInteractCalledAndNotCollect(); - const interactRequest = await collectEndpointAsserter.getInteractRequest(); - await collectEndpointAsserter.reset(); - // If an identity has not been established, we hit the interact endpoint using - // fetch even though the user may be navigating away from the page. In the - // real world where we're not blocking navigation, Alloy may - // or may not get a response back before navigation completes. If Alloy does not - // receive a response back, an identity cookie will not have been established, unfortunately, - // but that is considered better than using sendBeacon that for sure would not establish - // an identity. - await assertRequestXdm(interactRequest); - - // Because an identity has been established, we can safely hit the collect - // endpoint using sendBeacon. - await clickLink(); - await collectEndpointAsserter.assertCollectCalledAndNotInteract(); -}); - -test("Test C8118: Verify that a download link click data is not sent when download link click collection is disabled", async () => { - const testConfig = compose(orgMainConfigMain, clickCollectionEnabled, { - clickCollection: { - downloadLinkEnabled: false, - eventGroupingEnabled: false, - }, - }); - const collectEndpointAsserter = await createCollectEndpointAsserter(); - const alloy = createAlloyProxy(); - await alloy.configure(testConfig); - await preventLinkNavigation(); - await addLinkToBody(DOWNLOAD_LINK_ANCHOR); - await clickLink(); - await collectEndpointAsserter.assertNeitherCollectNorInteractCalled(); -}); - -test("Test C8118: Verify that a download link click data is sent when download link click collection is enabled", async () => { - const testConfig = compose(orgMainConfigMain, clickCollectionEnabled, { - clickCollection: { - downloadLinkEnabled: true, - eventGroupingEnabled: false, - }, - }); - const collectEndpointAsserter = await createCollectEndpointAsserter(); - const alloy = createAlloyProxy(); - await alloy.configure(testConfig); - await preventLinkNavigation(); - await addLinkToBody(DOWNLOAD_LINK_ANCHOR); - await clickLink(); - await collectEndpointAsserter.assertInteractCalledAndNotCollect(); - const interactRequest = await collectEndpointAsserter.getInteractRequest(); - const webInteraction = await getWebInteractionFromRequest(interactRequest); - await t.expect(webInteraction).eql({ - name: "Download Zip File", - region: "BODY", - type: "download", - URL: "https://alloyio.com/functional-test/example.zip", - linkClicks: { value: 1 }, - }); - const activityMapData = getActivityMapDataFromRequest(interactRequest); - await t.expect(activityMapData).eql({ - page: "https://alloyio.com/functional-test/testPage.html", - link: "Download Zip File", - region: "BODY", - pageIDType: 0, - }); -}); - -test("Test C8118: Verify that a internal link click data is not sent when internal link click collection is disabled", async () => { - const testConfig = compose(orgMainConfigMain, clickCollectionEnabled, { - clickCollection: { - internalLinkEnabled: false, - eventGroupingEnabled: false, - }, - }); - const collectEndpointAsserter = await createCollectEndpointAsserter(); - const alloy = createAlloyProxy(); - await alloy.configure(testConfig); - await preventLinkNavigation(); - await addLinkToBody(INTERNAL_LINK_ANCHOR_1); - await clickLink(); - await collectEndpointAsserter.assertNeitherCollectNorInteractCalled(); -}); - -test("Test C8118: Verify that a internal link click data is sent when internal link click collection is enabled", async () => { - const testConfig = compose(orgMainConfigMain, clickCollectionEnabled, { - clickCollection: { - internalLinkEnabled: true, - eventGroupingEnabled: false, - }, - }); - const collectEndpointAsserter = await createCollectEndpointAsserter(); - const alloy = createAlloyProxy(); - await alloy.configure(testConfig); - await preventLinkNavigation(); - await addLinkToBody(INTERNAL_LINK_ANCHOR_2); - await clickLink(); - await collectEndpointAsserter.assertInteractCalledAndNotCollect(); - const interactRequest = await collectEndpointAsserter.getInteractRequest(); - const webInteraction = await getWebInteractionFromRequest(interactRequest); - await t.expect(webInteraction).eql({ - name: "Internal Link", - region: "BODY", - type: "other", - URL: "https://alloyio.com/functional-test/blank.html", - linkClicks: { value: 1 }, - }); - const activityMapData = getActivityMapDataFromRequest(interactRequest); - await t.expect(activityMapData).eql({ - page: "https://alloyio.com/functional-test/testPage.html", - link: "Internal Link", - region: "BODY", - pageIDType: 0, - }); -}); - -test("Test C8118: Verify that a external link click data is not sent when external link click collection is disabled", async () => { - const testConfig = compose(orgMainConfigMain, clickCollectionEnabled, { - clickCollection: { - externalLinkEnabled: false, - eventGroupingEnabled: false, - }, - }); - const collectEndpointAsserter = await createCollectEndpointAsserter(); - const alloy = createAlloyProxy(); - await alloy.configure(testConfig); - await preventLinkNavigation(); - await addLinkToBody(EXTERNAL_LINK_ANCHOR); - await clickLink(); - await collectEndpointAsserter.assertNeitherCollectNorInteractCalled(); -}); - -test("Test C8118: Verify that a external link click data is sent when external link click collection is enabled", async () => { - const testConfig = compose(orgMainConfigMain, clickCollectionEnabled, { - clickCollection: { - externalLinkEnabled: true, - eventGroupingEnabled: false, - }, - }); - const collectEndpointAsserter = await createCollectEndpointAsserter(); - const alloy = createAlloyProxy(); - await alloy.configure(testConfig); - await preventLinkNavigation(); - await addLinkToBody(EXTERNAL_LINK_ANCHOR); - await clickLink(); - await collectEndpointAsserter.assertInteractCalledAndNotCollect(); - const interactRequest = await collectEndpointAsserter.getInteractRequest(); - const webInteraction = await getWebInteractionFromRequest(interactRequest); - await t.expect(webInteraction).eql({ - name: "External Link", - region: "BODY", - type: "exit", - URL: "https://example.com/", - linkClicks: { value: 1 }, - }); - const activityMapData = getActivityMapDataFromRequest(interactRequest); - await t.expect(activityMapData).eql({ - page: "https://alloyio.com/functional-test/testPage.html", - link: "External Link", - region: "BODY", - pageIDType: 0, - }); -}); - -test("Test C8118: Verify that a internal link click data is not sent when event grouping is enabled", async () => { - const testConfig = compose(orgMainConfigMain, clickCollectionEnabled, { - clickCollection: { - internalLinkEnabled: true, - eventGroupingEnabled: true, - }, - }); - const collectEndpointAsserter = await createCollectEndpointAsserter(); - const alloy = createAlloyProxy(); - await alloy.configure(testConfig); - await preventLinkNavigation(); - await addLinkToBody(INTERNAL_LINK_ANCHOR_1); - await clickLink(); - await collectEndpointAsserter.assertNeitherCollectNorInteractCalled(); -}); - -test("Test C8118: Verify cached internal link click data is sent on the next page view event", async () => { - const testConfig = compose(orgMainConfigMain, clickCollectionEnabled, { - clickCollection: { - internalLinkEnabled: true, - eventGroupingEnabled: true, - }, - }); - const collectEndpointAsserter = await createCollectEndpointAsserter(); - const alloy = createAlloyProxy(); - await alloy.configure(testConfig); - await preventLinkNavigation(); - await addLinkToBody(INTERNAL_LINK_ANCHOR_1); - await clickLink(); - await collectEndpointAsserter.assertNeitherCollectNorInteractCalled(); - await collectEndpointAsserter.reset(); - await alloy.sendEvent({ - xdm: { - web: { - eventType: "web.webpagedetails.pageViews", - webPageDetails: { - name: "Test Page", - pageViews: { - value: 1, - }, - }, - }, - }, - }); - await collectEndpointAsserter.assertInteractCalledAndNotCollect(); - const interactRequest = await collectEndpointAsserter.getInteractRequest(); - const xdm = await getXdmFromRequest(interactRequest); - await t.expect(xdm.web.webInteraction).eql({ - name: "Test Link", - region: "BODY", - type: "other", - URL: "https://alloyio.com/functional-test/blank.html", - linkClicks: { value: 1 }, - }); - await t.expect(xdm.web.webPageDetails).eql({ - URL: "https://alloyio.com/functional-test/testPage.html", - name: "Test Page", - pageViews: { value: 1 }, - }); - const activityMapData = getActivityMapDataFromRequest(interactRequest); - await t.expect(activityMapData).eql({ - page: "https://alloyio.com/functional-test/testPage.html", - link: "Test Link", - region: "BODY", - pageIDType: 0, - }); -}); - -test("Test C8118: Verify internal link click data with custom region", async () => { - const testConfig = compose(orgMainConfigMain, clickCollectionEnabled, { - clickCollection: { - internalLinkEnabled: true, - eventGroupingEnabled: false, - }, - }); - const collectEndpointAsserter = await createCollectEndpointAsserter(); - const alloy = createAlloyProxy(); - await alloy.configure(testConfig); - await preventLinkNavigation(); - await addHtmlToBody( - '', - ); - await clickLink(); - await collectEndpointAsserter.assertInteractCalledAndNotCollect(); - const interactRequest = await collectEndpointAsserter.getInteractRequest(); - const webInteraction = await getWebInteractionFromRequest(interactRequest); - await t.expect(webInteraction.region).eql("custom-region"); -}); - -test("Test C8118: Verify external link click data with custom link type", async () => { - const testConfig = compose(orgMainConfigMain, clickCollectionEnabled, { - clickCollection: { - externalLinkEnabled: true, - eventGroupingEnabled: false, - }, - }); - const collectEndpointAsserter = await createCollectEndpointAsserter(); - const alloy = createAlloyProxy(); - await alloy.configure(testConfig); - await preventLinkNavigation(); - await addLinkToBody( - 'External Link', - ); - await clickLink(); - await collectEndpointAsserter.assertInteractCalledAndNotCollect(); - const interactRequest = await collectEndpointAsserter.getInteractRequest(); - const webInteraction = await getWebInteractionFromRequest(interactRequest); - await t.expect(webInteraction.type).eql("exit"); -}); - -test("Test C8118: Verify link click with custom activity map data", async () => { - const testConfig = compose(orgMainConfigMain, clickCollectionEnabled, { - clickCollection: { - internalLinkEnabled: true, - eventGroupingEnabled: false, - }, - }); - const collectEndpointAsserter = await createCollectEndpointAsserter(); - const alloy = createAlloyProxy(); - await alloy.configure(testConfig); - await preventLinkNavigation(); - await addHtmlToBody( - '', - ); - await clickLink(); - await collectEndpointAsserter.assertInteractCalledAndNotCollect(); - const interactRequest = await collectEndpointAsserter.getInteractRequest(); - const activityMapData = getActivityMapDataFromRequest(interactRequest); - - // Check each property individually - await t - .expect(activityMapData.page) - .eql("https://alloyio.com/functional-test/testPage.html"); - await t.expect(activityMapData.link).eql("Custom Activity Map Link"); - await t.expect(activityMapData.region).eql("custom-region"); - await t.expect(activityMapData.pageIDType).eql(0); - - // If all individual checks pass, then do the full object comparison - await t.expect(activityMapData).eql({ - page: "https://alloyio.com/functional-test/testPage.html", - link: "Custom Activity Map Link", - region: "custom-region", - pageIDType: 0, - }); -}); - -test("Test C8118: Verify multiple link clicks with event grouping enabled", async () => { - const testConfig = compose(orgMainConfigMain, clickCollectionEnabled, { - clickCollection: { - internalLinkEnabled: true, - eventGroupingEnabled: true, - }, - }); - const collectEndpointAsserter = await createCollectEndpointAsserter(); - const alloy = createAlloyProxy(); - await alloy.configure(testConfig); - await preventLinkNavigation(); - await addLinkToBody('Link 1'); - await addLinkToBody('Link 2'); - - await t.click(Selector("#alloy-link-test-1")); - await t.click(Selector("#alloy-link-test-2")); - - await collectEndpointAsserter.assertNeitherCollectNorInteractCalled(); - await collectEndpointAsserter.reset(); - - await alloy.sendEvent({ - xdm: { - web: { - eventType: "web.webpagedetails.pageViews", - webPageDetails: { - name: "Test Page", - pageViews: { value: 1 }, - }, - }, - }, - }); - - await collectEndpointAsserter.assertInteractCalledAndNotCollect(); - const interactRequest = await collectEndpointAsserter.getInteractRequest(); - const xdm = await getXdmFromRequest(interactRequest); - - if (Array.isArray(xdm.web.webInteraction)) { - await t.expect(xdm.web.webInteraction.length).eql(2); - await t.expect(xdm.web.webInteraction[0].name).eql("Link 1"); - await t.expect(xdm.web.webInteraction[1].name).eql("Link 2"); - } else if (xdm.web.webInteraction) { - await t.expect(xdm.web.webInteraction.name).eql("Link 2"); - } else { - await t.fail("No webInteraction data found in XDM"); - } -}); - -test("Test C8118: Verify link click with custom XDM data", async () => { - const testConfig = compose(orgMainConfigMain, clickCollectionEnabled, { - clickCollection: { - internalLinkEnabled: true, - eventGroupingEnabled: false, - }, - onBeforeLinkClickSend: (options) => { - options.xdm.customField = "customValue"; - return true; - }, - }); - const collectEndpointAsserter = await createCollectEndpointAsserter(); - const alloy = createAlloyProxy(); - await alloy.configure(testConfig); - await preventLinkNavigation(); - await addLinkToBody(INTERNAL_LINK_ANCHOR_2); - - await clickLink(); - await collectEndpointAsserter.assertInteractCalledAndNotCollect(); - const interactRequest = await collectEndpointAsserter.getInteractRequest(); - const xdm = await getXdmFromRequest(interactRequest); - await t.expect(xdm.customField).eql("customValue"); -}); - -test("Test C8118: Verify storePageViewProperties functionality", async () => { - const testConfig = compose(orgMainConfigMain, clickCollectionEnabled, { - clickCollection: { - eventGroupingEnabled: true, - }, - }); - const collectEndpointAsserter = await createCollectEndpointAsserter(); - const alloy = createAlloyProxy(); - await alloy.configure(testConfig); - await preventLinkNavigation(); - await addLinkToBody(INTERNAL_LINK_ANCHOR_1); - await clickLink(); - - await alloy.sendEvent({ - xdm: { - web: { - webPageDetails: { - name: "Test Page", - }, - }, - }, - }); - - await collectEndpointAsserter.assertInteractCalledAndNotCollect(); - const interactRequest = await collectEndpointAsserter.getInteractRequest(); - const xdm = await getXdmFromRequest(interactRequest); - await t.expect(xdm.web.webPageDetails.name).eql("Test Page"); - await t - .expect(xdm.web.webInteraction) - .ok("Web interaction should be present"); -}); diff --git a/packages/core/test/functional/specs/Data Collector/C81181.js b/packages/core/test/functional/specs/Data Collector/C81181.js deleted file mode 100644 index fbed04d41..000000000 --- a/packages/core/test/functional/specs/Data Collector/C81181.js +++ /dev/null @@ -1,330 +0,0 @@ -/* -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, Selector } from "testcafe"; -import createFixture from "../../helpers/createFixture/index.js"; -import addHtmlToBody from "../../helpers/dom/addHtmlToBody.js"; -import { - compose, - orgMainConfigMain, - clickCollectionEnabled, - clickCollectionEventGroupingDisabled, - clickCollectionSessionStorageDisabled, -} from "../../helpers/constants/configParts/index.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; -import preventLinkNavigation from "../../helpers/preventLinkNavigation.js"; -import createCollectEndpointAsserter from "../../helpers/createCollectEndpointAsserter.js"; - -createFixture({ - title: "C81181: Test onBeforeLinkClickSend callback", -}); - -test.meta({ - ID: "C81181", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -const addLinksToBody = () => { - return addHtmlToBody( - `Test Link - Link Click that is canceled`, - ); -}; - -const clickLink = async (selector) => { - await t.click(Selector(selector)); -}; - -const assertRequestXdm = async ( - request, - expectedXdmWebInteraction, - expectedData, -) => { - const requestBody = JSON.parse(request.request.body); - const eventXdm = requestBody.events[0].xdm; - const eventData = requestBody.events[0].data; - await t.expect(eventXdm.eventType).eql("web.webinteraction.linkClicks"); - await t.expect(eventXdm.web.webInteraction).eql(expectedXdmWebInteraction); - if (expectedData) { - await t.expect(eventData).eql(expectedData); - } -}; - -test("Test C81181: Verify that onBeforeLinkClickSend cancels a request", async () => { - const collectEndpointAsserter = await createCollectEndpointAsserter(); - await preventLinkNavigation(); - const alloy = createAlloyProxy(); - - const testConfig = compose(orgMainConfigMain, clickCollectionEnabled, { - onBeforeLinkClickSend: () => { - return false; - }, - }); - await alloy.configure(testConfig); - await addLinksToBody(); - await clickLink("#alloy-link-test"); - await collectEndpointAsserter.assertNeitherCollectNorInteractCalled(); -}); - -test("Test C81181: Verify that filterClickDetails can cancel a request", async () => { - const collectEndpointAsserter = await createCollectEndpointAsserter(); - await preventLinkNavigation(); - const alloy = createAlloyProxy(); - const testConfig = compose(orgMainConfigMain, clickCollectionEnabled, { - clickCollection: { - filterClickDetails: () => { - return false; - }, - }, - }); - await alloy.configure(testConfig); - await addLinksToBody(); - await clickLink("#alloy-link-test"); - await collectEndpointAsserter.assertNeitherCollectNorInteractCalled(); -}); - -test("Test C81181: Verify that if onBeforeLinkClickSend not defined and clickCollectionEnabled link clicks are collected", async () => { - const collectEndpointAsserter = await createCollectEndpointAsserter(); - await preventLinkNavigation(); - const alloy = createAlloyProxy(); - const testConfig = compose( - orgMainConfigMain, - clickCollectionEnabled, - clickCollectionEventGroupingDisabled, - ); - await alloy.configure(testConfig); - await addLinksToBody(); - await clickLink("#alloy-link-test"); - await collectEndpointAsserter.assertInteractCalledAndNotCollect(); - const interactRequest = collectEndpointAsserter.getInteractRequest(); - const expectedXdm = { - name: "Test Link", - region: "BODY", - type: "other", - URL: "https://alloyio.com/functional-test/valid.html", - linkClicks: { value: 1 }, - }; - await assertRequestXdm(interactRequest, expectedXdm); -}); - -test("Test C81181: Verify that onBeforeLinkClickSend cancels a request based on link details", async () => { - const collectEndpointAsserter = await createCollectEndpointAsserter(); - await preventLinkNavigation(); - const alloy = createAlloyProxy(); - - const testConfig = compose( - orgMainConfigMain, - clickCollectionEnabled, - clickCollectionEventGroupingDisabled, - { - onBeforeLinkClickSend: (options) => { - const { clickedElement } = options; - return clickedElement.id !== "canceled-alloy-link-test"; - }, - }, - ); - await alloy.configure(testConfig); - await addLinksToBody(); - await clickLink("#canceled-alloy-link-test"); - await collectEndpointAsserter.assertNeitherCollectNorInteractCalled(); - await clickLink("#alloy-link-test"); - await collectEndpointAsserter.assertInteractCalledAndNotCollect(); - const interactRequest = collectEndpointAsserter.getInteractRequest(); - const expectedXdm = { - name: "Test Link", - region: "BODY", - type: "other", - URL: "https://alloyio.com/functional-test/valid.html", - linkClicks: { value: 1 }, - }; - await assertRequestXdm(interactRequest, expectedXdm); -}); - -test("Test C81181: Verify that filterClickDetails can cancels a request based on link details", async () => { - const collectEndpointAsserter = await createCollectEndpointAsserter(); - await preventLinkNavigation(); - const alloy = createAlloyProxy(); - - const testConfig = compose(orgMainConfigMain, clickCollectionEnabled, { - clickCollection: { - eventGroupingEnabled: false, - filterClickDetails: (props) => { - return props.clickedElement.id !== "canceled-alloy-link-test"; - }, - }, - }); - await alloy.configure(testConfig); - await addLinksToBody(); - await clickLink("#canceled-alloy-link-test"); - await collectEndpointAsserter.assertNeitherCollectNorInteractCalled(); - await clickLink("#alloy-link-test"); - await collectEndpointAsserter.assertInteractCalledAndNotCollect(); - const interactRequest = collectEndpointAsserter.getInteractRequest(); - const expectedXdm = { - name: "Test Link", - region: "BODY", - type: "other", - URL: "https://alloyio.com/functional-test/valid.html", - linkClicks: { value: 1 }, - }; - await assertRequestXdm(interactRequest, expectedXdm); -}); - -test("Test C81181: Verify that onBeforeLinkClickSend augments a request", async () => { - const collectEndpointAsserter = await createCollectEndpointAsserter(); - await preventLinkNavigation(); - const alloy = createAlloyProxy(); - - const testConfig = compose( - orgMainConfigMain, - clickCollectionEnabled, - clickCollectionEventGroupingDisabled, - { - onBeforeLinkClickSend: (options) => { - const { xdm, data, clickedElement } = options; - - if (clickedElement.id === "alloy-link-test") { - xdm.web.webInteraction.name = "Augmented name"; - data.customField = "test123"; - - return true; - } - return false; - }, - }, - ); - - await alloy.configure(testConfig); - await addLinksToBody(); - await clickLink("#canceled-alloy-link-test"); - await collectEndpointAsserter.assertNeitherCollectNorInteractCalled(); - await clickLink("#alloy-link-test"); - await collectEndpointAsserter.assertInteractCalledAndNotCollect(); - const interactRequest = collectEndpointAsserter.getInteractRequest(); - - const expectedXdmWebInteraction = { - name: "Augmented name", - region: "BODY", - type: "other", - URL: "https://alloyio.com/functional-test/valid.html", - linkClicks: { value: 1 }, - }; - - const expectedData = { - __adobe: { - analytics: { - contextData: { - a: { - activitymap: { - link: "Test Link", - page: "https://alloyio.com/functional-test/testPage.html", - pageIDType: 0, - region: "BODY", - }, - }, - }, - }, - }, - customField: "test123", - }; - - await assertRequestXdm( - interactRequest, - expectedXdmWebInteraction, - expectedData, - ); -}); - -test("Test C81181: Verify that filterClickDetails can augment a request", async () => { - const collectEndpointAsserter = await createCollectEndpointAsserter(); - await preventLinkNavigation(); - const alloy = createAlloyProxy(); - - const testConfig = compose(orgMainConfigMain, clickCollectionEnabled, { - clickCollection: { - eventGroupingEnabled: false, - filterClickDetails: (props) => { - if (props.clickedElement.id === "alloy-link-test") { - props.linkName = "Augmented name"; - return true; - } - return false; - }, - }, - }); - - await alloy.configure(testConfig); - await addLinksToBody(); - await clickLink("#canceled-alloy-link-test"); - await collectEndpointAsserter.assertNeitherCollectNorInteractCalled(); - await clickLink("#alloy-link-test"); - await collectEndpointAsserter.assertInteractCalledAndNotCollect(); - const interactRequest = collectEndpointAsserter.getInteractRequest(); - - const expectedXdmWebInteraction = { - name: "Augmented name", - region: "BODY", - type: "other", - URL: "https://alloyio.com/functional-test/valid.html", - linkClicks: { value: 1 }, - }; - - const expectedData = { - __adobe: { - analytics: { - contextData: { - a: { - activitymap: { - link: "Augmented name", - page: "https://alloyio.com/functional-test/testPage.html", - pageIDType: 0, - region: "BODY", - }, - }, - }, - }, - }, - }; - - await assertRequestXdm( - interactRequest, - expectedXdmWebInteraction, - expectedData, - ); -}); - -test("Test C81181: Verify disabling session storage still captures link click data", async () => { - const collectEndpointAsserter = await createCollectEndpointAsserter(); - await preventLinkNavigation(); - const alloy = createAlloyProxy(); - - const testConfig = compose( - orgMainConfigMain, - clickCollectionEnabled, - clickCollectionEventGroupingDisabled, - clickCollectionSessionStorageDisabled, - ); - - await alloy.configure(testConfig); - await addLinksToBody(); - await clickLink("#alloy-link-test"); - await collectEndpointAsserter.assertInteractCalledAndNotCollect(); - const interactRequest = collectEndpointAsserter.getInteractRequest(); - const expectedXdm = { - name: "Test Link", - region: "BODY", - type: "other", - URL: "https://alloyio.com/functional-test/valid.html", - linkClicks: { value: 1 }, - }; - await assertRequestXdm(interactRequest, expectedXdm); -}); diff --git a/packages/core/test/functional/specs/Data Collector/C81182.js b/packages/core/test/functional/specs/Data Collector/C81182.js deleted file mode 100644 index b2e831ae4..000000000 --- a/packages/core/test/functional/specs/Data Collector/C81182.js +++ /dev/null @@ -1,165 +0,0 @@ -/* -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, Selector } from "testcafe"; -import createFixture from "../../helpers/createFixture/index.js"; -import addHtmlToBody from "../../helpers/dom/addHtmlToBody.js"; -import { - compose, - orgMainConfigMain, - clickCollectionEnabled, - clickCollectionDisabled, -} from "../../helpers/constants/configParts/index.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; -import preventLinkNavigation from "../../helpers/preventLinkNavigation.js"; -import { TEST_PAGE as TEST_PAGE_URL } from "../../helpers/constants/url.js"; -import createNetworkLogger from "../../helpers/networkLogger/index.js"; - -const networkLogger = createNetworkLogger(); - -createFixture({ - title: - "C81182: Test onBeforeLinkClickSend callback when personalization metric involved", - url: `${TEST_PAGE_URL}?test=C81182`, - requestHooks: [networkLogger.edgeEndpointLogs], -}); - -test.meta({ - ID: "C81182", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -const addLinkToBody = () => { - return addHtmlToBody( - `Link Click that is canceled`, - ); -}; - -const clickLink = async (selector) => { - await t.click(Selector(selector)); -}; - -const expectedExprienceDecisioning = { - propositionEventType: { - interact: 1, - }, - propositions: [ - { - id: "AT:eyJhY3Rpdml0eUlkIjoiMTQ1NDQ4IiwiZXhwZXJpZW5jZUlkIjoiIn0=", - scope: "__view__", - scopeDetails: { - decisionProvider: "TGT", - activity: { - id: "145448", - }, - characteristics: { - eventToken: "VwlBQpRYFcQXcG9jkRhiRA==", - }, - }, - }, - ], -}; - -const assertRequestXdm = async ( - request, - expectedWebInteraction, - expectedData, -) => { - const requestBody = JSON.parse(request.request.body); - const eventXdm = requestBody.events[0].xdm; - const eventData = requestBody.events[0].data; - await t.expect(eventXdm.eventType).eql("decisioning.propositionInteract"); - await t.expect(eventXdm.web.webInteraction).eql(expectedWebInteraction); - await t.expect(eventData).eql(expectedData); - await t - // eslint-disable-next-line no-underscore-dangle - .expect(eventXdm._experience.decisioning) - .eql(expectedExprienceDecisioning); -}; - -test.skip("Test C81182: Verify that onBeforeLinkClickSend removes the link-click details when personalization metric on link", async () => { - await preventLinkNavigation(); - const alloy = createAlloyProxy(); - - const testConfig = compose(orgMainConfigMain, clickCollectionEnabled, { - onBeforeLinkClickSend: (options) => { - const { data } = options; - - data.customField = "test"; - - return false; - }, - }); - await alloy.configure(testConfig); - await alloy.sendEvent({ renderDecisions: true }); - - await clickLink("#alloy-link-test"); - await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(3); - const linkClickRequest = networkLogger.edgeEndpointLogs.requests[2]; - await assertRequestXdm(linkClickRequest, undefined, undefined); -}); - -test.skip("Test C81182: Verify that onBeforeLinkClickSend augments request when personalization metric on link", async () => { - await preventLinkNavigation(); - const alloy = createAlloyProxy(); - - const testConfig = compose(orgMainConfigMain, clickCollectionEnabled, { - onBeforeLinkClickSend: (options) => { - const { xdm, data, clickedElement } = options; - - if (clickedElement.id === "alloy-link-test") { - xdm.web.webInteraction.name = "augmented link name"; - xdm.web.webInteraction.region = "BODY"; - data.customField = "test123"; - return true; - } - - return false; - }, - }); - await alloy.configure(testConfig); - await addLinkToBody(); - await alloy.sendEvent({ renderDecisions: true }); - - await clickLink("#alloy-link-test"); - await clickLink("#canceled-alloy-link-test"); - - const expectedXdmWebInteraction = { - name: "augmented link name", - region: "BODY", - type: "other", - URL: "https://alloyio.com/functional-test/valid.html", - linkClicks: { value: 1 }, - }; - await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(3); - const linkClickRequest = networkLogger.edgeEndpointLogs.requests[2]; - await assertRequestXdm(linkClickRequest, expectedXdmWebInteraction, { - customField: "test123", - }); -}); - -test.skip("Test C81182: Verify that personalization metric is sent when clickCollection is disabled", async () => { - await preventLinkNavigation(); - const alloy = createAlloyProxy(); - - const testConfig = compose(orgMainConfigMain, clickCollectionDisabled); - await alloy.configure(testConfig); - await addLinkToBody(); - await alloy.sendEvent({ renderDecisions: true }); - - await clickLink("#alloy-link-test"); - await clickLink("#canceled-alloy-link-test"); - - await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(3); - const linkClickRequest = networkLogger.edgeEndpointLogs.requests[2]; - await assertRequestXdm(linkClickRequest, undefined, undefined); -}); diff --git a/packages/core/test/functional/specs/Data Collector/C81183.js b/packages/core/test/functional/specs/Data Collector/C81183.js deleted file mode 100644 index d2ce463d8..000000000 --- a/packages/core/test/functional/specs/Data Collector/C81183.js +++ /dev/null @@ -1,146 +0,0 @@ -/* -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 addHtmlToBody from "../../helpers/dom/addHtmlToBody.js"; -import { - compose, - orgMainConfigMain, - clickCollectionEnabled, - clickCollectionDisabled, -} from "../../helpers/constants/configParts/index.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; - -const alloyMonitorScript = ` -window.__alloyMonitors = window.__alloyMonitors || []; -window.__alloyMonitors.push({ - onInstanceConfigured: function(data) { - window.___getLinkDetails = data.getLinkDetails; - } - });`; - -createFixture({ - title: "C81181: getLinkDetails monitoring hook function", - monitoringHooksScript: alloyMonitorScript, -}); - -test.meta({ - ID: "C81181", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -const addLinksToBody = () => { - return addHtmlToBody( - `Test Link - Link Click that is canceled`, - ); -}; - -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 C81183: Verify that it returns the object augmented by onBeforeLinkClickSend", async () => { - const alloy = createAlloyProxy(); - - const testConfig = compose(orgMainConfigMain, clickCollectionEnabled, { - onBeforeLinkClickSend: (options) => { - const { xdm, data, clickedElement } = options; - if (clickedElement.id === "cancel-alloy-link-test") { - return false; - } - xdm.web.webInteraction.name = "augmented name"; - data.customField = "test123"; - - return true; - }, - }); - const expectedLinkDetails = { - linkName: "Test Link", - linkRegion: "BODY", - linkType: "other", - linkUrl: "https://alloyio.com/functional-test/valid.html", - pageName: "https://alloyio.com/functional-test/testPage.html", - }; - - await alloy.configure(testConfig); - await addLinksToBody(); - const result = await getLinkDetails("alloy-link-test"); - await t.expect(result).eql(expectedLinkDetails); -}); - -test("Test C81183: Verify that it returns undefined if onBeforeLinkClickSend returns false", async () => { - const alloy = createAlloyProxy(); - - const testConfig = compose(orgMainConfigMain, clickCollectionEnabled, { - onBeforeLinkClickSend: (options) => { - const { xdm, data, clickedElement } = options; - if (clickedElement.id === "cancel-alloy-link-test") { - return false; - } - xdm.web.webInteraction.name = "augmented name"; - data.customField = "test123"; - - return true; - }, - }); - - await alloy.configure(testConfig); - await addLinksToBody(); - const linkDetails = await getLinkDetails("cancel-alloy-link-test"); - await t.wait(10000); - await t.expect(linkDetails).eql({ - linkName: undefined, - linkRegion: undefined, - linkType: undefined, - linkUrl: undefined, - pageName: undefined, - }); -}); - -test("Test C81183: Verify that it returns linkDetails irrespective on clickCollectionEnabled", async () => { - const alloy = createAlloyProxy(); - - const testConfig = compose(orgMainConfigMain, clickCollectionDisabled); - - await alloy.configure(testConfig); - await addLinksToBody(); - const expectedLinkDetails = { - linkName: "Test Link", - linkRegion: "BODY", - linkType: "other", - linkUrl: "https://alloyio.com/functional-test/valid.html", - pageName: "https://alloyio.com/functional-test/testPage.html", - }; - - await t.expect(getLinkDetails("cancel-alloy-link-test")).eql({ - linkName: undefined, - linkRegion: undefined, - linkType: undefined, - linkUrl: undefined, - pageName: undefined, - }); - await t.expect(getLinkDetails("alloy-link-test")).eql(expectedLinkDetails); -}); diff --git a/packages/core/test/functional/specs/Data Collector/C81184.js b/packages/core/test/functional/specs/Data Collector/C81184.js deleted file mode 100644 index a45d3986f..000000000 --- a/packages/core/test/functional/specs/Data Collector/C81184.js +++ /dev/null @@ -1,146 +0,0 @@ -/* -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. -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/packages/core/test/functional/specs/Data Collector/C8119.js b/packages/core/test/functional/specs/Data Collector/C8119.js deleted file mode 100644 index 289bc379d..000000000 --- a/packages/core/test/functional/specs/Data Collector/C8119.js +++ /dev/null @@ -1,55 +0,0 @@ -/* -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, Selector } from "testcafe"; -import createFixture from "../../helpers/createFixture/index.js"; -import addHtmlToBody from "../../helpers/dom/addHtmlToBody.js"; -import { - compose, - orgMainConfigMain, -} from "../../helpers/constants/configParts/index.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; -import preventLinkNavigation from "../../helpers/preventLinkNavigation.js"; -import createCollectEndpointAsserter from "../../helpers/createCollectEndpointAsserter.js"; - -createFixture({ - title: - "C8119: Does not send event with information about link clicks if disabled.", -}); - -test.meta({ - ID: "C8119", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -const addLinkToBody = () => { - return addHtmlToBody( - `Test Link`, - ); -}; - -const clickLink = async () => { - await t.click(Selector("#alloy-link-test")); -}; - -test("Test C8119: Load page with link. Click link. Verify no event sent.", async () => { - const collectEndpointAsserter = await createCollectEndpointAsserter(); - await preventLinkNavigation(); - const alloy = createAlloyProxy(); - const testConfig = compose(orgMainConfigMain, { - clickCollectionEnabled: false, - }); - await alloy.configure(testConfig); - await addLinkToBody(); - await clickLink(); - await collectEndpointAsserter.assertNeitherCollectNorInteractCalled(); -}); diff --git a/packages/core/test/functional/specs/Data Collector/C9369211.js b/packages/core/test/functional/specs/Data Collector/C9369211.js deleted file mode 100644 index a68343b01..000000000 --- a/packages/core/test/functional/specs/Data Collector/C9369211.js +++ /dev/null @@ -1,70 +0,0 @@ -/* -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 } from "testcafe"; -import createNetworkLogger from "../../helpers/networkLogger/index.js"; -import { responseStatus } from "../../helpers/assertions/index.js"; -import createFixture from "../../helpers/createFixture/index.js"; -import { - compose, - orgMainConfigMain, - debugEnabled, -} from "../../helpers/constants/configParts/index.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; -import { TEST_PAGE } from "../../helpers/constants/url.js"; -import createCollectEndpointAsserter from "../../helpers/createCollectEndpointAsserter.js"; - -const networkLogger = createNetworkLogger(); -const config = compose(orgMainConfigMain, debugEnabled); - -createFixture({ - title: "C9369211: sendEvent includes a header for the referer", - requestHooks: [ - networkLogger.edgeEndpointLogs, - networkLogger.edgeCollectEndpointLogs, - ], -}); - -test.meta({ - ID: "C9369211", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -test("Test C9369211: sendEvent includes a header for the referer when calling interact.", async () => { - const alloy = createAlloyProxy(); - await alloy.configure(config); - await alloy.sendEvent({}); - - await responseStatus(networkLogger.edgeEndpointLogs.requests, [200, 207]); - await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(1); - - await t - .expect(networkLogger.edgeEndpointLogs.requests[0].request.headers.referer) - .eql(TEST_PAGE); -}); - -test("Test C9369211: sendEvent includes a header for the referer when calling collect.", async () => { - const collectEndpointAsserter = await createCollectEndpointAsserter(); - - const alloy = createAlloyProxy(); - await alloy.configure(config); - await alloy.sendEvent({}); // establish an identity - await collectEndpointAsserter.reset(); - await alloy.sendEvent({ documentUnloading: true }); - await collectEndpointAsserter.assertCollectCalledAndNotInteract(); - - // TODO: Testcafe no longer captures the request body for sendBeacon requests. - // We could enhance this test to use Assurance to verify the request body. - // await t - // .expect(collectEndpointAsserter.getCollectRequest().request.headers.referer) - // .eql(TEST_PAGE); -}); diff --git a/packages/core/test/functional/specs/ID Migration/C14394.js b/packages/core/test/functional/specs/ID Migration/C14394.js deleted file mode 100644 index 3e880e1f4..000000000 --- a/packages/core/test/functional/specs/ID Migration/C14394.js +++ /dev/null @@ -1,73 +0,0 @@ -/* -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 } from "testcafe"; -import createNetworkLogger from "../../helpers/networkLogger/index.js"; -import getResponseBody from "../../helpers/networkLogger/getResponseBody.js"; -import { responseStatus } from "../../helpers/assertions/index.js"; -import createFixture from "../../helpers/createFixture/index.js"; -import createResponse from "../../helpers/createResponse.js"; -import { - compose, - orgMainConfigMain, - debugEnabled, - migrationEnabled, -} from "../../helpers/constants/configParts/index.js"; -import setLegacyIdentityCookie from "../../helpers/setLegacyIdentityCookie.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; - -const config = compose(orgMainConfigMain, debugEnabled, migrationEnabled); - -const networkLogger = createNetworkLogger(); - -createFixture({ - title: - "C14394: When ID migration is enabled and no identity cookie is found but legacy identity cookie is found, the ECID will be sent on the request", - requestHooks: [networkLogger.edgeEndpointLogs], -}); - -test.meta({ - ID: "C14394", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -test("Test C14394: When ID migration is enabled and no identity cookie is found but legacy identity cookie is found, the ECID will be sent on the request", async () => { - await setLegacyIdentityCookie(orgMainConfigMain.orgId); - - const alloy = createAlloyProxy(); - await alloy.configure(config); - await alloy.sendEvent({ renderDecisions: true }); - - await responseStatus(networkLogger.edgeEndpointLogs.requests, [200, 207]); - - const request = JSON.parse( - networkLogger.edgeEndpointLogs.requests[0].request.body, - ); - - await t - .expect(request.xdm.identityMap.ECID[0].id) - .eql("16908443662402872073525706953453086963"); - - const response = JSON.parse( - getResponseBody(networkLogger.edgeEndpointLogs.requests[0]), - ); - - const payloads = createResponse({ content: response }).getPayloadsByType( - "identity:result", - ); - - const ecidPayload = payloads.filter( - (payload) => payload.namespace.code === "ECID", - )[0]; - - await t.expect(ecidPayload.id).eql("16908443662402872073525706953453086963"); -}); diff --git a/packages/core/test/functional/specs/ID Migration/C14399.js b/packages/core/test/functional/specs/ID Migration/C14399.js deleted file mode 100644 index fe32d5001..000000000 --- a/packages/core/test/functional/specs/ID Migration/C14399.js +++ /dev/null @@ -1,83 +0,0 @@ -/* -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 createNetworkLogger from "../../helpers/networkLogger/index.js"; -import getResponseBody from "../../helpers/networkLogger/getResponseBody.js"; -import { responseStatus } from "../../helpers/assertions/index.js"; -import createFixture from "../../helpers/createFixture/index.js"; -import createResponse from "../../helpers/createResponse.js"; -import { - compose, - orgMainConfigMain, - debugEnabled, - migrationEnabled, -} from "../../helpers/constants/configParts/index.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; - -const config = compose(orgMainConfigMain, debugEnabled, migrationEnabled); - -const networkLogger = createNetworkLogger(); - -createFixture({ - title: - "C14399: When ID migration is enabled and no identity cookie is found but legacy s_ecid cookie is found, the ECID will be sent on the request", - requestHooks: [networkLogger.edgeEndpointLogs], -}); - -test.meta({ - ID: "C14399", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -const setEcidCookie = ClientFunction(() => { - document.cookie = "s_ecid=MCMID%7C16908443662402872073525706953453086963"; -}); - -const getDocumentCookie = ClientFunction(() => document.cookie); - -test("Test C14399: When ID migration is enabled and no identity cookie is found but legacy s_ecid cookie is found, the ECID will be sent on the request", async () => { - await setEcidCookie(); - const alloy = createAlloyProxy(); - await alloy.configure(config); - await alloy.sendEvent({ renderDecisions: true }); - - await responseStatus(networkLogger.edgeEndpointLogs.requests, [200, 207]); - - const request = JSON.parse( - networkLogger.edgeEndpointLogs.requests[0].request.body, - ); - - await t - .expect(request.xdm.identityMap.ECID[0].id) - .eql("16908443662402872073525706953453086963"); - - const response = JSON.parse( - getResponseBody(networkLogger.edgeEndpointLogs.requests[0]), - ); - - const payloads = createResponse({ content: response }).getPayloadsByType( - "identity:result", - ); - - const ecidPayload = payloads.filter( - (payload) => payload.namespace.code === "ECID", - )[0]; - - await t.expect(ecidPayload.id).eql("16908443662402872073525706953453086963"); - - const documentCookie = await getDocumentCookie(); - - await t - .expect(documentCookie) - .contains("s_ecid=MCMID%7C16908443662402872073525706953453086963"); -}); diff --git a/packages/core/test/functional/specs/ID Migration/C14400.js b/packages/core/test/functional/specs/ID Migration/C14400.js deleted file mode 100644 index 53c8277a5..000000000 --- a/packages/core/test/functional/specs/ID Migration/C14400.js +++ /dev/null @@ -1,84 +0,0 @@ -/* -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 createNetworkLogger from "../../helpers/networkLogger/index.js"; -import getResponseBody from "../../helpers/networkLogger/getResponseBody.js"; -import { responseStatus } from "../../helpers/assertions/index.js"; -import createFixture from "../../helpers/createFixture/index.js"; -import createResponse from "../../helpers/createResponse.js"; -import { ECID as ECID_REGEX } from "../../helpers/constants/regex.js"; -import { - compose, - orgMainConfigMain, - debugEnabled, - migrationDisabled, -} from "../../helpers/constants/configParts/index.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; - -const config = compose(orgMainConfigMain, debugEnabled, migrationDisabled); - -const networkLogger = createNetworkLogger(); - -createFixture({ - title: - "C14400: When ID migration is disabled and no identity cookie is found but legacy s_ecid cookie is found, the ECID should not be sent on the request", - requestHooks: [networkLogger.edgeEndpointLogs], -}); - -test.meta({ - ID: "C14400", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -const setEcidCookie = ClientFunction(() => { - document.cookie = "s_ecid=MCMID%7C16908443662402872073525706953453086963"; -}); - -const getDocumentCookie = ClientFunction(() => document.cookie); - -test("Test C14400: When ID migration is disabled and no identity cookie is found but legacy s_ecid cookie is found, the ECID should not be sent on the request", async () => { - await setEcidCookie(); - const alloy = createAlloyProxy(); - await alloy.configure(config); - await alloy.sendEvent({ renderDecisions: true }); - - await responseStatus(networkLogger.edgeEndpointLogs.requests, [200, 207]); - - const request = JSON.parse( - networkLogger.edgeEndpointLogs.requests[0].request.body, - ); - - await t.expect(request.xdm).eql(undefined); - - const response = JSON.parse( - getResponseBody(networkLogger.edgeEndpointLogs.requests[0]), - ); - - const payloads = createResponse({ content: response }).getPayloadsByType( - "identity:result", - ); - - const ecidPayload = payloads.filter( - (payload) => payload.namespace.code === "ECID", - )[0]; - - await t.expect(ecidPayload.id).match(ECID_REGEX); - - const documentCookie = await getDocumentCookie(); - - await t - .expect(documentCookie) - .notContains( - `AMCV_5BFE274A5F6980A50A495C08%40AdobeOrg=MCMID|${ecidPayload.id}`, - ); -}); diff --git a/packages/core/test/functional/specs/ID Migration/C14401.js b/packages/core/test/functional/specs/ID Migration/C14401.js deleted file mode 100644 index aebc29acd..000000000 --- a/packages/core/test/functional/specs/ID Migration/C14401.js +++ /dev/null @@ -1,71 +0,0 @@ -/* -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 } from "testcafe"; -import createNetworkLogger from "../../helpers/networkLogger/index.js"; -import getResponseBody from "../../helpers/networkLogger/getResponseBody.js"; -import { responseStatus } from "../../helpers/assertions/index.js"; -import createFixture from "../../helpers/createFixture/index.js"; -import createResponse from "../../helpers/createResponse.js"; -import { ECID as ECID_REGEX } from "../../helpers/constants/regex.js"; -import { - compose, - orgMainConfigMain, - debugEnabled, - migrationDisabled, -} from "../../helpers/constants/configParts/index.js"; -import setLegacyIdentityCookie from "../../helpers/setLegacyIdentityCookie.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; - -const config = compose(orgMainConfigMain, debugEnabled, migrationDisabled); - -const networkLogger = createNetworkLogger(); - -createFixture({ - title: - "C14401: When ID migration is disabled and no identity cookie is found but legacy identity cookie is found, the ECID will not be sent on the request", - requestHooks: [networkLogger.edgeEndpointLogs], -}); - -test.meta({ - ID: "C14401", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -test("Test C14401: When ID migration is disabled and no identity cookie is found but legacy identity cookie is found, the ECID will not be sent on the request", async () => { - await setLegacyIdentityCookie(orgMainConfigMain.orgId); - const alloy = createAlloyProxy(); - await alloy.configure(config); - await alloy.sendEvent({ renderDecisions: true }); - - await responseStatus(networkLogger.edgeEndpointLogs.requests, [200, 207]); - - const request = JSON.parse( - networkLogger.edgeEndpointLogs.requests[0].request.body, - ); - - await t.expect(request.xdm).eql(undefined); - - const response = JSON.parse( - getResponseBody(networkLogger.edgeEndpointLogs.requests[0]), - ); - - const payloads = createResponse({ content: response }).getPayloadsByType( - "identity:result", - ); - - const ecidPayload = payloads.filter( - (payload) => payload.namespace.code === "ECID", - )[0]; - - await t.expect(ecidPayload.id).match(ECID_REGEX); -}); diff --git a/packages/core/test/functional/specs/ID Migration/C14402.js b/packages/core/test/functional/specs/ID Migration/C14402.js deleted file mode 100644 index ee0c497f4..000000000 --- a/packages/core/test/functional/specs/ID Migration/C14402.js +++ /dev/null @@ -1,93 +0,0 @@ -/* -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 createNetworkLogger from "../../helpers/networkLogger/index.js"; -import getResponseBody from "../../helpers/networkLogger/getResponseBody.js"; -import { responseStatus } from "../../helpers/assertions/index.js"; -import createFixture from "../../helpers/createFixture/index.js"; -import createResponse from "../../helpers/createResponse.js"; -import { ECID as ECID_REGEX } from "../../helpers/constants/regex.js"; -import { - compose, - orgMainConfigMain, - debugEnabled, - migrationEnabled, -} from "../../helpers/constants/configParts/index.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; -import { - LEGACY_IDENTITY_COOKIE_NAME, - LEGACY_IDENTITY_COOKIE_UNESCAPED_NAME, -} from "../../helpers/constants/cookies.js"; -import createConsoleLogger from "../../helpers/consoleLogger/index.js"; - -const config = compose(orgMainConfigMain, debugEnabled, migrationEnabled); - -const networkLogger = createNetworkLogger(); - -createFixture({ - title: - "C14402: When ID migration is enabled and no legacy AMCV cookie is found, an AMCV cookie should be created", - requestHooks: [networkLogger.edgeEndpointLogs], -}); - -test.meta({ - ID: "C14402", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -const getDocumentCookie = ClientFunction(() => document.cookie); - -test("Test C14402: When ID migration is enabled and no legacy AMCV cookie is found, an AMCV cookie should be created", async () => { - const logger = await createConsoleLogger(); - const alloy = createAlloyProxy(); - await alloy.configure(config); - await logger.reset(); - await alloy.sendEvent({ renderDecisions: true }); - - await responseStatus(networkLogger.edgeEndpointLogs.requests, [200, 207]); - - const response = JSON.parse( - getResponseBody(networkLogger.edgeEndpointLogs.requests[0]), - ); - - const payloads = createResponse({ content: response }).getPayloadsByType( - "identity:result", - ); - - const ecidPayload = payloads.filter( - (payload) => payload.namespace.code === "ECID", - )[0]; - - await t.expect(ecidPayload.id).match(ECID_REGEX); - - const documentCookie = await getDocumentCookie(); - - await t - .expect(documentCookie) - .contains(`${LEGACY_IDENTITY_COOKIE_NAME}=MCMID|${ecidPayload.id}`); - - const logs = await logger.info.getMessagesSinceReset(); - const setCookieAttributes = logs - .filter( - (message) => message.length === 3 && message[1] === "Setting cookie", - ) - .map((message) => message[2]) - .filter( - (cookieSettings) => - cookieSettings.name === LEGACY_IDENTITY_COOKIE_UNESCAPED_NAME, - ); - - await t.expect(setCookieAttributes.length).eql(1); - await t.expect(setCookieAttributes[0].sameSite).eql("none"); - await t.expect(setCookieAttributes[0].secure).eql(true); -}); diff --git a/packages/core/test/functional/specs/ID Migration/C14403.js b/packages/core/test/functional/specs/ID Migration/C14403.js deleted file mode 100644 index 76e62c813..000000000 --- a/packages/core/test/functional/specs/ID Migration/C14403.js +++ /dev/null @@ -1,73 +0,0 @@ -/* -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 createNetworkLogger from "../../helpers/networkLogger/index.js"; -import getResponseBody from "../../helpers/networkLogger/getResponseBody.js"; -import { responseStatus } from "../../helpers/assertions/index.js"; -import createFixture from "../../helpers/createFixture/index.js"; -import createResponse from "../../helpers/createResponse.js"; -import { ECID as ECID_REGEX } from "../../helpers/constants/regex.js"; -import { - compose, - orgMainConfigMain, - debugEnabled, - migrationDisabled, -} from "../../helpers/constants/configParts/index.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; - -const config = compose(orgMainConfigMain, debugEnabled, migrationDisabled); - -const networkLogger = createNetworkLogger(); - -createFixture({ - title: - "C14403: When ID migration is disabled and no legacy AMCV cookie is found, no AMCV cookie should be created", - requestHooks: [networkLogger.edgeEndpointLogs], -}); - -test.meta({ - ID: "C14403", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -const getDocumentCookie = ClientFunction(() => document.cookie); - -test("Test C14403: When ID migration is disabled and no legacy AMCV cookie is found, no AMCV cookie should be created", async () => { - const alloy = createAlloyProxy(); - await alloy.configure(config); - await alloy.sendEvent({ renderDecisions: true }); - - await responseStatus(networkLogger.edgeEndpointLogs.requests, [200, 207]); - - const response = JSON.parse( - getResponseBody(networkLogger.edgeEndpointLogs.requests[0]), - ); - - const payloads = createResponse({ content: response }).getPayloadsByType( - "identity:result", - ); - - const ecidPayload = payloads.filter( - (payload) => payload.namespace.code === "ECID", - )[0]; - - await t.expect(ecidPayload.id).match(ECID_REGEX); - - const documentCookie = await getDocumentCookie(); - - await t - .expect(documentCookie) - .notContains( - `AMCV_5BFE274A5F6980A50A495C08%40AdobeOrg=MCMID|${ecidPayload.id}`, - ); -}); diff --git a/packages/core/test/functional/specs/ID Migration/C5752639.js b/packages/core/test/functional/specs/ID Migration/C5752639.js deleted file mode 100644 index 9021c6bc0..000000000 --- a/packages/core/test/functional/specs/ID Migration/C5752639.js +++ /dev/null @@ -1,73 +0,0 @@ -/* -Copyright 2022 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 { - compose, - orgMainConfigMain, - debugEnabled, - migrationEnabled, -} from "../../helpers/constants/configParts/index.js"; -import createNetworkLogger from "../../helpers/networkLogger/index.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; -import reloadPage from "../../helpers/reloadPage.js"; -import createRandomEcid from "../../helpers/createRandomEcid.js"; -import createAdobeMC from "../../helpers/createAdobeMC.js"; -import getReturnedEcid from "../../helpers/networkLogger/getReturnedEcid.js"; -import setLegacyIdentityCookie from "../../helpers/setLegacyIdentityCookie.js"; -import { LEGACY_IDENTITY_COOKIE_NAME } from "../../helpers/constants/cookies.js"; - -const config = compose(orgMainConfigMain, debugEnabled, migrationEnabled); - -const networkLogger = createNetworkLogger(); - -const id = createRandomEcid(); -const adobemc = createAdobeMC({ id }); - -createFixture({ - title: - "C5752639: Identity can be changed via the adobe_mc query string parameter when id_migration is enabled", - requestHooks: [networkLogger.edgeEndpointLogs], -}); - -test.meta({ - ID: "C5752639", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -const getDocumentCookie = ClientFunction(() => document.cookie); - -test("C5752639: Identity can be changed via the adobe_mc query string parameter when id_migration is enabled", async () => { - setLegacyIdentityCookie(); - - const alloy = createAlloyProxy(); - await alloy.configure(config); - await alloy.sendEvent({}); - - await reloadPage(`adobe_mc=${adobemc}`); - await alloy.configure(config); - await alloy.sendEvent({}); - - await reloadPage(""); - await alloy.configure(config); - await alloy.sendEvent({}); - - const documentCookie = await getDocumentCookie(); - await t - .expect(documentCookie) - .contains(`${LEGACY_IDENTITY_COOKIE_NAME}=MCMID|${id}`); - - const ecid = getReturnedEcid(networkLogger.edgeEndpointLogs.requests[2]); - await t.expect(ecid).eql(id); -}); diff --git a/packages/core/test/functional/specs/Identity/C10922.js b/packages/core/test/functional/specs/Identity/C10922.js deleted file mode 100644 index 4644cf461..000000000 --- a/packages/core/test/functional/specs/Identity/C10922.js +++ /dev/null @@ -1,157 +0,0 @@ -/* -Copyright 2020 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 } from "testcafe"; -import createNetworkLogger from "../../helpers/networkLogger/index.js"; -import createFixture from "../../helpers/createFixture/index.js"; -import { - compose, - edgeDomainThirdParty, - edgeDomainFirstParty, - orgMainConfigMain, - thirdPartyCookiesDisabled, - thirdPartyCookiesEnabled, - migrationEnabled, - migrationDisabled, -} from "../../helpers/constants/configParts/index.js"; -import reloadPage from "../../helpers/reloadPage.js"; -import setLegacyIdentityCookie from "../../helpers/setLegacyIdentityCookie.js"; -import areThirdPartyCookiesSupported from "../../helpers/areThirdPartyCookiesSupported.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; - -const networkLogger = createNetworkLogger(); - -const demdexHostRegex = /\.demdex\.net/; - -const getHostForFirstRequest = () => { - const firstRequest = networkLogger.edgeInteractEndpointLogs.requests[0]; - return firstRequest.request.url; -}; - -const assertRequestWentToDemdex = async () => { - await t.expect(getHostForFirstRequest()).match(demdexHostRegex); -}; - -const assertRequestDidNotGoToDemdex = async () => { - await t.expect(getHostForFirstRequest()).notMatch(demdexHostRegex); -}; - -createFixture({ - title: "C10922 - demdex usage", - requestHooks: [networkLogger.edgeInteractEndpointLogs], -}); - -fixture.beforeEach(async () => { - await setLegacyIdentityCookie(orgMainConfigMain.orgId); -}); - -test.meta({ - ID: "C10922", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -const permutationsUsingDemdex = [ - { - description: "third-party cookies enabled", - config: compose( - orgMainConfigMain, - thirdPartyCookiesEnabled, - edgeDomainThirdParty, - migrationDisabled, - ), - }, - { - description: "third-party cookies enabled and first-party edge domain", - config: compose( - orgMainConfigMain, - thirdPartyCookiesEnabled, - edgeDomainFirstParty, - migrationDisabled, - ), - }, - { - // If we have a identity to migrate, we still want to hit demdex because - // demdex will use our ECID to set the third-party cookie if the third-party - // cookie isn't already set, which provides for better cross-domain - // identification for future requests. - description: - "third-party cookies enabled and migration enabled with existing legacy identity cookie", - config: compose( - orgMainConfigMain, - thirdPartyCookiesEnabled, - edgeDomainThirdParty, - migrationEnabled, - ), - }, -]; - -permutationsUsingDemdex.forEach((permutation) => { - test(`C10922 - demdex is used for first request when configured with ${permutation.description} and browser supports third-party cookies by default`, async () => { - const alloy = createAlloyProxy(); - await alloy.configure(permutation.config); - await alloy.sendEvent(); - - if (areThirdPartyCookiesSupported()) { - await assertRequestWentToDemdex(); - } else { - await assertRequestDidNotGoToDemdex(); - } - await networkLogger.clearLogs(); - await reloadPage(); - await alloy.configure(permutation.config); - await alloy.sendEvent(); - // The request should not have gone to the third-party domain - // because we already have an identity cookie. - await assertRequestDidNotGoToDemdex(); - }); -}); - -const permutationsNotUsingDemdex = [ - { - description: "third-party cookies disabled", - config: compose( - orgMainConfigMain, - thirdPartyCookiesDisabled, - edgeDomainThirdParty, - migrationDisabled, - ), - }, - { - description: "third-party cookies disabled and first-party edge domain", - config: compose( - orgMainConfigMain, - thirdPartyCookiesDisabled, - edgeDomainFirstParty, - migrationDisabled, - ), - }, - { - description: - "third-party cookies disabled and migration enabled with existing legacy identity cookie", - config: compose( - orgMainConfigMain, - thirdPartyCookiesDisabled, - edgeDomainFirstParty, - migrationEnabled, - ), - }, -]; - -permutationsNotUsingDemdex.forEach((permutation) => { - test(`C10922 - demdex is not used when configured with ${permutation.description}`, async () => { - const alloy = createAlloyProxy(); - await alloy.configure(permutation.config); - await alloy.sendEvent(); - await assertRequestDidNotGoToDemdex(); - }); -}); diff --git a/packages/core/test/functional/specs/Identity/C14699834.js b/packages/core/test/functional/specs/Identity/C14699834.js deleted file mode 100644 index 2b9a7e9cd..000000000 --- a/packages/core/test/functional/specs/Identity/C14699834.js +++ /dev/null @@ -1,119 +0,0 @@ -/* -Copyright 2022 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 } from "testcafe"; -import { - compose, - orgMainConfigMain, - thirdPartyCookiesDisabled, - debugEnabled, - edgeDomainFirstParty, -} from "../../helpers/constants/configParts/index.js"; -import { TEST_PAGE } from "../../helpers/constants/url.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; -import createFixture from "../../helpers/createFixture/index.js"; -import cookies from "../../helpers/cookies.js"; -import { MAIN_IDENTITY_COOKIE_NAME } from "../../helpers/constants/cookies.js"; -import { CONSENT_IN } from "../../helpers/constants/consent.js"; - -createFixture({ - url: TEST_PAGE, - title: "C14699834: Identity is still established if first request fails", -}); - -test.meta({ - ID: "C9999999", - SEVERTIY: "P0", - TEST_RUN: "Regression", -}); - -const config = compose( - orgMainConfigMain, - thirdPartyCookiesDisabled, - debugEnabled, - edgeDomainFirstParty, -); - -test("C14699834: Identity is still established if the first send event fails", async () => { - const alloy = createAlloyProxy(); - await alloy.configure(config); - const errorMessage = await alloy.sendEventErrorMessage({ - xdm: { - identityMap: { - ECID: [ - { - id: "INVALID_ID", - }, - ], - }, - }, - }); - await t.expect(await errorMessage).contains("INVALID_ID"); - // make sure we don't have an ECID - const identityCookieValue1 = await cookies.get(MAIN_IDENTITY_COOKIE_NAME); - await t - .expect(identityCookieValue1) - .notOk("Identity cookie found prematurely."); - - await alloy.sendEvent({}); - - // make sure we have an ecid - const identityCookieValue2 = await cookies.get(MAIN_IDENTITY_COOKIE_NAME); - await t.expect(identityCookieValue2).ok("No identity cookie found."); -}); - -test("C14699834: Identity is still established if the first set consent fails", async () => { - const alloy = createAlloyProxy(); - await alloy.configure(config); - const errorMessage = await alloy.setConsentErrorMessage({ - identityMap: { - ECID: [ - { - id: "INVALID_ID", - }, - ], - }, - ...CONSENT_IN, - }); - await t.expect(await errorMessage).contains("INVALID_ID"); - // make sure we don't have an ECID - const identityCookieValue1 = await cookies.get(MAIN_IDENTITY_COOKIE_NAME); - await t - .expect(identityCookieValue1) - .notOk("Identity cookie found prematurely."); - - await alloy.setConsent(CONSENT_IN); - - // make sure we have an ecid - const identityCookieValue2 = await cookies.get(MAIN_IDENTITY_COOKIE_NAME); - await t.expect(identityCookieValue2).ok("No identity cookie found."); -}); - -test("C14699834: Identity is still established if the first get identity fails", async () => { - const alloy = createAlloyProxy(); - await alloy.configure(config); - const errorMessage = await alloy.getIdentityErrorMessage({ - edgeConfigOverrides: { myinvalidoverride: "myvalue" }, - }); - await t.expect(await errorMessage).contains("myinvalidoverride"); - // make sure we don't have an ECID - const identityCookieValue1 = await cookies.get(MAIN_IDENTITY_COOKIE_NAME); - await t - .expect(identityCookieValue1) - .notOk("Identity cookie found prematurely."); - - await alloy.getIdentity(); - - // make sure we have an ecid - const identityCookieValue2 = await cookies.get(MAIN_IDENTITY_COOKIE_NAME); - await t.expect(identityCookieValue2).ok("No identity cookie found."); -}); diff --git a/packages/core/test/functional/specs/Identity/C15325238.js b/packages/core/test/functional/specs/Identity/C15325238.js deleted file mode 100644 index 62539231c..000000000 --- a/packages/core/test/functional/specs/Identity/C15325238.js +++ /dev/null @@ -1,75 +0,0 @@ -/* -Copyright 2022 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 } from "testcafe"; -import createFixture from "../../helpers/createFixture/index.js"; -import { SECONDARY_TEST_PAGE, TEST_PAGE } from "../../helpers/constants/url.js"; -import { - compose, - orgMainConfigMain, - debugEnabled, - thirdPartyCookiesDisabled, -} from "../../helpers/constants/configParts/index.js"; -import createNetworkLogger from "../../helpers/networkLogger/index.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; -import getReturnedEcid from "../../helpers/networkLogger/getReturnedEcid.js"; - -// We disable third party cookies so that the domains don't share identities -// through the demdex cookies. -const config = compose( - orgMainConfigMain, - debugEnabled, - thirdPartyCookiesDisabled, -); - -const networkLogger = createNetworkLogger(); - -createFixture({ - title: - "C15325238: When there are multiple adobe_mc parameters, the last one is used.", - requestHooks: [networkLogger.edgeEndpointLogs], -}); - -test.meta({ - ID: "C15325238", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -test("C15325238: When there are multiple adobe_mc parameters, the last one is used.", async () => { - const alloy = createAlloyProxy(); - await alloy.configure(config); - await alloy.sendEvent({}); - const { url: newUrl1 } = await alloy.appendIdentityToUrl({ - url: TEST_PAGE, - }); - - await t.navigateTo(SECONDARY_TEST_PAGE); - await alloy.configure(config); - await alloy.sendEvent({}); - - const { url: newUrl2 } = await alloy.appendIdentityToUrl({ - url: newUrl1, - }); - - await t.navigateTo(newUrl2); - await alloy.configure(config); - await alloy.sendEvent({}); - - const [ecid1, ecid2, ecid3] = - networkLogger.edgeEndpointLogs.requests.map(getReturnedEcid); - await t.expect(ecid1).notEql(ecid2); - await t.expect(ecid2).eql(ecid3); - - const { identity } = await alloy.getIdentity(); - await t.expect(identity.ECID).eql(ecid2); -}); diff --git a/packages/core/test/functional/specs/Identity/C1703722.js b/packages/core/test/functional/specs/Identity/C1703722.js deleted file mode 100644 index 140bffdd4..000000000 --- a/packages/core/test/functional/specs/Identity/C1703722.js +++ /dev/null @@ -1,50 +0,0 @@ -/* -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 } from "testcafe"; -import createFixture from "../../helpers/createFixture/index.js"; -import cookies from "../../helpers/cookies.js"; -import { - compose, - orgMainConfigMain, - debugEnabled, -} from "../../helpers/constants/configParts/index.js"; -import { MAIN_IDENTITY_COOKIE_NAME } from "../../helpers/constants/cookies.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; -import createNetworkLogger from "../../helpers/networkLogger/index.js"; - -const debugEnabledConfig = compose(orgMainConfigMain, debugEnabled); - -const networkLogger = createNetworkLogger(); - -createFixture({ - title: "C1703722: getIdentity works when first command after configure", - requestHooks: [networkLogger.acquireEndpointLogs], -}); - -test.meta({ - ID: "C1703772", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -test("C1703722: getIdentity works when first command after configure", async () => { - const alloy = createAlloyProxy(); - await alloy.configure(debugEnabledConfig); - // this should get an ECID - const identityResponse = await alloy.getIdentity(); - - await t.expect(networkLogger.acquireEndpointLogs.requests.length).eql(1); - const identityCookieValue = await cookies.get(MAIN_IDENTITY_COOKIE_NAME); - await t.expect(identityCookieValue).ok("No identity cookie set."); - await t.expect(identityResponse.identity).ok("No ecid returned"); - await t.expect(identityResponse.edge.regionId).gt(0); -}); diff --git a/packages/core/test/functional/specs/Identity/C1703723.js b/packages/core/test/functional/specs/Identity/C1703723.js deleted file mode 100644 index 6a7ff3e15..000000000 --- a/packages/core/test/functional/specs/Identity/C1703723.js +++ /dev/null @@ -1,52 +0,0 @@ -/* -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 } from "testcafe"; -import createFixture from "../../helpers/createFixture/index.js"; -import cookies from "../../helpers/cookies.js"; -import { - compose, - orgMainConfigMain, - debugEnabled, -} from "../../helpers/constants/configParts/index.js"; -import { MAIN_IDENTITY_COOKIE_NAME } from "../../helpers/constants/cookies.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; -import createNetworkLogger from "../../helpers/networkLogger/index.js"; - -const debugEnabledConfig = compose(orgMainConfigMain, debugEnabled); - -const networkLogger = createNetworkLogger(); - -createFixture({ - title: - "C1703723: getIdentity uses cached values when interact already called", - requestHooks: [networkLogger.acquireEndpointLogs], -}); - -test.meta({ - ID: "C1703773", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -test("C1703723: getIdentity uses cached values when interact already called", async () => { - const alloy = createAlloyProxy(); - await alloy.configure(debugEnabledConfig); - // this should get an ECID - await alloy.sendEvent(); - const identityResponse = await alloy.getIdentity(); - - await t.expect(networkLogger.acquireEndpointLogs.requests.length).eql(0); - const identityCookieValue = await cookies.get(MAIN_IDENTITY_COOKIE_NAME); - await t.expect(identityCookieValue).ok("No identity cookie set."); - await t.expect(identityResponse.identity).ok("No ecid returned"); - await t.expect(identityResponse.edge.regionId).gt(0); -}); diff --git a/packages/core/test/functional/specs/Identity/C19160486.js b/packages/core/test/functional/specs/Identity/C19160486.js deleted file mode 100644 index a5ce20b95..000000000 --- a/packages/core/test/functional/specs/Identity/C19160486.js +++ /dev/null @@ -1,176 +0,0 @@ -/* -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 } from "testcafe"; -import createFixture from "../../helpers/createFixture/index.js"; -import { - compose, - orgMainConfigMain, - debugEnabled, - thirdPartyCookiesEnabled, - thirdPartyCookiesDisabled, -} from "../../helpers/constants/configParts/index.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; -import createNetworkLogger from "../../helpers/networkLogger/index.js"; -import areThirdPartyCookiesSupported from "../../helpers/areThirdPartyCookiesSupported.js"; -import { SECONDARY_TEST_PAGE } from "../../helpers/constants/url.js"; -import reloadPage from "../../helpers/reloadPage.js"; - -const thirdPartyCookiesEnabledConfig = compose( - orgMainConfigMain, - debugEnabled, - thirdPartyCookiesEnabled, -); -const thirdPartyCookiesDisabledConfig = compose( - orgMainConfigMain, - debugEnabled, - thirdPartyCookiesDisabled, -); - -const networkLogger = createNetworkLogger(); - -createFixture({ - title: "C19160486: The CORE identity is returned correctly from getIdentity", - requestHooks: [ - networkLogger.edgeEndpointLogs, - networkLogger.acquireEndpointLogs, - ], -}); - -test.meta({ - ID: "C19160486", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -test("C19160486: CORE identity is the same across domains when called first", async () => { - const alloy = createAlloyProxy(); - await alloy.configure(thirdPartyCookiesEnabledConfig); - const { - identity: { ECID: ecid1, CORE: core1 }, - } = await alloy.getIdentity({ namespaces: ["ECID", "CORE"] }); - await t.navigateTo(SECONDARY_TEST_PAGE); - - await alloy.configure(thirdPartyCookiesEnabledConfig); - const { - identity: { ECID: ecid2, CORE: core2 }, - } = await alloy.getIdentity({ namespaces: ["ECID", "CORE"] }); - - if (areThirdPartyCookiesSupported()) { - // ecids are the same because the same orgId is used to go from CORE -> ECID - await t.expect(ecid1).eql(ecid2); - await t.expect(core1).eql(core2); - await t.expect(ecid1).notEql(core1); - } else { - // ecids are different because third party cookies are not written - await t.expect(ecid1).notEql(ecid2); - // CORE identity is null because Experience Edge only creates it when called on demdex domain - // which only happens on Chrome browsers. - await t.expect(core1).eql(null); - await t.expect(core2).eql(null); - } -}); - -test("C19160486: CORE identity is the same across domains when called after sendEvent", async () => { - const alloy = createAlloyProxy(); - await alloy.configure(thirdPartyCookiesEnabledConfig); - await alloy.sendEvent(); - const { - identity: { ECID: ecid1, CORE: core1 }, - } = await alloy.getIdentity({ namespaces: ["ECID", "CORE"] }); - await t.expect(networkLogger.acquireEndpointLogs.requests.length).eql(0); - await t.navigateTo(SECONDARY_TEST_PAGE); - - await alloy.configure(thirdPartyCookiesEnabledConfig); - await alloy.sendEvent(); - const { - identity: { ECID: ecid2, CORE: core2 }, - } = await alloy.getIdentity({ namespaces: ["ECID", "CORE"] }); - await t.expect(networkLogger.acquireEndpointLogs.requests.length).eql(0); - - if (areThirdPartyCookiesSupported()) { - // ecids are the same because the same orgId is used to go from CORE -> ECID - await t.expect(ecid1).eql(ecid2); - await t.expect(core1).eql(core2); - await t.expect(ecid1).notEql(core1); - } else { - // ecids are different because third party cookies are not written - await t.expect(ecid1).notEql(ecid2); - // CORE identity is null because Experience Edge only creates it when called on demdex domain - // which only happens on Chrome browsers. - await t.expect(core1).eql(null); - await t.expect(core2).eql(null); - } -}); - -test("C19160486: CORE identity is not requested when third party cookies are disabled", async () => { - const alloy = createAlloyProxy(); - await alloy.configure(thirdPartyCookiesDisabledConfig); - await alloy.sendEvent(); - await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(1); - await t.expect(networkLogger.edgeEndpointLogs.count(() => true)).eql(1); - const requestBody = JSON.parse( - networkLogger.edgeEndpointLogs.requests[0].request.body, - ); - await t.expect(requestBody.query.identity.fetch).eql(["ECID"]); -}); - -test("C19160486: CORE identity cannot be requested from getIdentity when third party cookies are disabled", async () => { - const alloy = createAlloyProxy(); - await alloy.configure(thirdPartyCookiesDisabledConfig); - const errorMessage = await alloy.getIdentityErrorMessage({ - namespaces: ["CORE"], - }); - await t - .expect(errorMessage) - .contains( - "The CORE namespace cannot be requested when third-party cookies are disabled", - ); -}); - -test("C19160486: Requesting CORE identity and ECID can be done separately", async () => { - const alloy = createAlloyProxy(); - await alloy.configure(thirdPartyCookiesEnabledConfig); - const { - identity: { ECID: ecid }, - } = await alloy.getIdentity({ namespaces: ["ECID"] }); - await t.expect(ecid).ok(); - const { - identity: { CORE: core }, - } = await alloy.getIdentity({ namespaces: ["CORE"] }); - if (areThirdPartyCookiesSupported()) { - await t.expect(core).ok(); - } else { - await t.expect(core).eql(null); - } -}); - -test("The CORE identity is returned correctly, even when the ECID is read from a cookie", async () => { - const alloy = createAlloyProxy(); - await alloy.configure(thirdPartyCookiesEnabledConfig); - - const { - identity: { ECID: networkEcid, CORE: networkCore }, - } = await alloy.getIdentity({ namespaces: ["ECID", "CORE"] }); - await t.expect(networkEcid).ok(); - await t.expect(networkCore).ok(); - - networkLogger.clearLogs(); - await reloadPage(); - - await alloy.configure(thirdPartyCookiesEnabledConfig); - const { - identity: { ECID: cookieEcid, CORE: newCore }, - } = await alloy.getIdentity({ namespaces: ["ECID", "CORE"] }); - - await t.expect(cookieEcid).eql(networkEcid); - await t.expect(newCore).ok(); -}); diff --git a/packages/core/test/functional/specs/Identity/C21636436.js b/packages/core/test/functional/specs/Identity/C21636436.js deleted file mode 100644 index 45e9bcd9a..000000000 --- a/packages/core/test/functional/specs/Identity/C21636436.js +++ /dev/null @@ -1,72 +0,0 @@ -/** - * Copyright 2025 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 } from "testcafe"; -import createNetworkLogger from "../../helpers/networkLogger/index.js"; -import createFixture from "../../helpers/createFixture/index.js"; -import { - compose, - orgMainConfigMain, - debugEnabled, -} from "../../helpers/constants/configParts/index.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; -import createCollectEndpointAsserter from "../../helpers/createCollectEndpointAsserter.js"; - -const networkLogger = createNetworkLogger(); -const config = compose(orgMainConfigMain, debugEnabled); - -createFixture({ - title: "C21636436: Get Identity after Collect Call", - requestHooks: [networkLogger.acquireEndpointLogs], -}); -test.meta({ - ID: "C21636436", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -test("Preserves ECID after sendEvent call with collect beacon", async () => { - const collectEndpointAsserter = await createCollectEndpointAsserter(); - const alloy = createAlloyProxy(); - await alloy.configure(config); - - await alloy.sendEvent(); - - await collectEndpointAsserter.reset(); - - const initialIdentity = await alloy.getIdentity({ - namespaces: ["ECID"], - }); - - await t - .expect(initialIdentity.identity.ECID) - .ok("No ECID in initial response"); - - const initialEcid = initialIdentity.identity.ECID; - - await alloy.sendEvent({ - documentUnloading: true, - xdm: { - eventType: "test-event", - }, - }); - - await collectEndpointAsserter.assertCollectCalledAndNotInteract(); - - const subsequentIdentity = await alloy.getIdentity({ - namespaces: ["ECID"], - }); - - await t - .expect(subsequentIdentity.identity.ECID) - .eql(initialEcid, "ECID was not preserved after collect call"); -}); diff --git a/packages/core/test/functional/specs/Identity/C21636437.js b/packages/core/test/functional/specs/Identity/C21636437.js deleted file mode 100644 index e10f69d56..000000000 --- a/packages/core/test/functional/specs/Identity/C21636437.js +++ /dev/null @@ -1,60 +0,0 @@ -/* -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 { t } from "testcafe"; -import createNetworkLogger from "../../helpers/networkLogger/index.js"; -import createFixture from "../../helpers/createFixture/index.js"; -import { - compose, - orgMainConfigMain, - thirdPartyCookiesEnabled, -} from "../../helpers/constants/configParts/index.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; -import demdexBlockerMock from "../../helpers/requestHooks/demdexBlockerMock.js"; - -const networkLogger = createNetworkLogger(); -const config = compose(orgMainConfigMain, thirdPartyCookiesEnabled); - -createFixture({ - title: "C21636437: Demdex Fallback Behavior", - requestHooks: [networkLogger.edgeEndpointLogs, demdexBlockerMock], -}); - -test.meta({ - ID: "C21636437", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -test("Continues collecting data when demdex is blocked", async () => { - const alloy = createAlloyProxy(); - - await alloy.configure(config); - await alloy.sendEvent(); - - // Get all requests - const requests = networkLogger.edgeEndpointLogs.requests; - - // Find the successful request (should be the last one) - const successfulRequest = requests[requests.length - 1]; - - // Verify the successful request - await t.expect(successfulRequest.request.url).notContains("demdex.net"); - await t.expect(successfulRequest.request.url).contains(config.edgeDomain); - await t.expect(successfulRequest.response.statusCode).eql(200); - - // Verify at least one request was successful - const successfulRequests = requests.filter( - (r) => - !r.request.url.includes("demdex.net") && r.response.statusCode === 200, - ); - await t.expect(successfulRequests.length).gte(1); -}); diff --git a/packages/core/test/functional/specs/Identity/C21636438.js b/packages/core/test/functional/specs/Identity/C21636438.js deleted file mode 100644 index 112e1a4f5..000000000 --- a/packages/core/test/functional/specs/Identity/C21636438.js +++ /dev/null @@ -1,118 +0,0 @@ -/* -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 { t } from "testcafe"; -import createNetworkLogger from "../../helpers/networkLogger/index.js"; -import createFixture from "../../helpers/createFixture/index.js"; -import { - compose, - orgMainConfigMain, - debugEnabled, -} from "../../helpers/constants/configParts/index.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; -import reloadPage from "../../helpers/reloadPage.js"; - -const networkLogger = createNetworkLogger(); -const config = compose(orgMainConfigMain, debugEnabled); - -createFixture({ - title: "C21636438: Decode the kndctr_ORGID_Identity cookie", - requestHooks: [networkLogger.acquireEndpointLogs], -}); - -test.meta({ - ID: "C21636438", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -test("Extracts information from kndctr cookie", async () => { - const alloy = createAlloyProxy(); - await alloy.configure(config); - - const { - identity: { ECID: networkEcid }, - } = await alloy.getIdentity(); - await t.expect(networkEcid).ok(); - await t.expect(networkLogger.acquireEndpointLogs.requests.length).eql(1); - - networkLogger.clearLogs(); - await reloadPage(); - - await alloy.configure(config); - const { - identity: { ECID: cookieEcid }, - } = await alloy.getIdentity(); - await t.expect(cookieEcid).eql(networkEcid); - await t.expect(networkLogger.acquireEndpointLogs.requests.length).eql(0); -}); - -test("Gracefully falls back to a network request if the cookie is not base64 encoded", async () => { - const alloy = createAlloyProxy(); - await alloy.configure(config); - // Establish the cookie - const { - identity: { ECID: networkEcid }, - } = await alloy.getIdentity(); - await t.expect(networkEcid).ok(); - await t.expect(networkLogger.acquireEndpointLogs.requests.length).eql(1); - // Change the cookie value to be gibberish - const orgId = config.orgId; - const cookieName = `kndctr_${orgId.replace("@", "_")}_identity`; - const cookieValue = "gibberish"; - /** @type { { name: string, value: string, domain: string }[] } */ - const [currentCookie] = await t.getCookies(cookieName); - await t.expect(currentCookie).ok(); - await t.setCookies({ ...currentCookie, value: cookieValue }); - - // Reload the page - networkLogger.clearLogs(); - await reloadPage(); - await alloy.configure(config); - - // Request the identity and ensure a network request was made - const { - identity: { ECID: cookieEcid }, - } = await alloy.getIdentity(); - await t.expect(networkLogger.acquireEndpointLogs.requests.length).eql(1); - await t.expect(cookieEcid).notEql(networkEcid); -}); - -test("Gracefully falls back to a network request if the cookie is base64 decoded but not a valid protobuf", async () => { - const alloy = createAlloyProxy(); - await alloy.configure(config); - // Establish the cookie - const { - identity: { ECID: networkEcid }, - } = await alloy.getIdentity(); - await t.expect(networkEcid).ok(); - await t.expect(networkLogger.acquireEndpointLogs.requests.length).eql(1); - // Change the cookie value to be gibberish - const orgId = config.orgId; - const cookieName = `kndctr_${orgId.replace("@", "_")}_identity`; - const cookieValue = Buffer.from([0x00, 0x00, 0x00, 0x00]).toString("base64"); - /** @type { { name: string, value: string, domain: string }[] } */ - const [currentCookie] = await t.getCookies(cookieName); - await t.expect(currentCookie).ok(); - await t.setCookies({ ...currentCookie, value: cookieValue }); - - // Reload the page - networkLogger.clearLogs(); - await reloadPage(); - await alloy.configure(config); - - // Request the identity and ensure a network request was made - const { - identity: { ECID: cookieEcid }, - } = await alloy.getIdentity(); - await t.expect(networkLogger.acquireEndpointLogs.requests.length).eql(1); - await t.expect(cookieEcid).notEql(networkEcid); -}); diff --git a/packages/core/test/functional/specs/Identity/C2581.js b/packages/core/test/functional/specs/Identity/C2581.js deleted file mode 100644 index 5d3433a36..000000000 --- a/packages/core/test/functional/specs/Identity/C2581.js +++ /dev/null @@ -1,57 +0,0 @@ -/* -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 } from "testcafe"; -import createFixture from "../../helpers/createFixture/index.js"; -import cookies from "../../helpers/cookies.js"; -import { - compose, - orgMainConfigMain, - debugEnabled, -} from "../../helpers/constants/configParts/index.js"; -import { MAIN_IDENTITY_COOKIE_NAME } from "../../helpers/constants/cookies.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; -import createNetworkLogger from "../../helpers/networkLogger/index.js"; - -const debugEnabledConfig = compose(orgMainConfigMain, debugEnabled); - -const networkLogger = createNetworkLogger(); - -createFixture({ - title: "C2581: Queue events when no ECID available on client", - requestHooks: [networkLogger.edgeEndpointLogs], -}); - -test.meta({ - ID: "C2581", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -test("Test C2581: Queue requests until we receive an ECID.", async () => { - const alloy = createAlloyProxy(); - await alloy.configure(debugEnabledConfig); - // this should get an ECID - await alloy.sendEventAsync(); - // this should wait until the first event returns - // so it can send the ECID in the request - await alloy.sendEvent(); - await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(2); - - // make sure we have an ecid - const identityCookieValue = await cookies.get(MAIN_IDENTITY_COOKIE_NAME); - await t.expect(identityCookieValue).ok("No identity cookie found."); - - // make sure the ecid was sent as part of the second request - await t - .expect(networkLogger.edgeEndpointLogs.requests[1].request.body) - .contains(identityCookieValue); -}); diff --git a/packages/core/test/functional/specs/Identity/C25822.js b/packages/core/test/functional/specs/Identity/C25822.js deleted file mode 100644 index 772a27e77..000000000 --- a/packages/core/test/functional/specs/Identity/C25822.js +++ /dev/null @@ -1,92 +0,0 @@ -/* -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 } from "testcafe"; -import createNetworkLogger from "../../helpers/networkLogger/index.js"; -import { responseStatus } from "../../helpers/assertions/index.js"; -import createFixture from "../../helpers/createFixture/index.js"; -import { - compose, - orgMainConfigMain, - debugEnabled, -} from "../../helpers/constants/configParts/index.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; - -const networkLogger = createNetworkLogger(); -const config = compose(orgMainConfigMain, debugEnabled); - -createFixture({ - title: "C25822: Event command sends a request with a validated identityMap", - requestHooks: [networkLogger.edgeEndpointLogs], -}); - -test.meta({ - ID: "C25822", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -const badAlloyEventOptions = { - xdm: { - identityMap: { - HYP: [ - { - id: 123, - }, - ], - }, - }, -}; - -test("C25822: Event command validates the identityMap", async () => { - const alloy = createAlloyProxy(); - await alloy.configure(config); - const errorMessage = await alloy.sendEventErrorMessage(badAlloyEventOptions); - await t - .expect(errorMessage) - .ok("Expected the sendEvent command to be rejected"); - - await t.expect(errorMessage).contains("xdm.identityMap.HYP[0].id"); -}); - -const goodAlloyEventOptions = { - xdm: { - identityMap: { - HYP: [ - { - id: "id123", - }, - ], - }, - }, -}; - -test("C25822: Event command sends the identityMap", async () => { - const alloy = createAlloyProxy(); - await alloy.configure(config); - await alloy.sendEvent(goodAlloyEventOptions); - - await responseStatus(networkLogger.edgeEndpointLogs.requests, [200, 207]); - - await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(1); - - const request = JSON.parse( - networkLogger.edgeEndpointLogs.requests[0].request.body, - ); - - await t.expect(request.events[0].xdm.identityMap).eql({ - HYP: [ - { - id: "id123", - }, - ], - }); -}); diff --git a/packages/core/test/functional/specs/Identity/C5287654.js b/packages/core/test/functional/specs/Identity/C5287654.js deleted file mode 100644 index 472db7c5b..000000000 --- a/packages/core/test/functional/specs/Identity/C5287654.js +++ /dev/null @@ -1,81 +0,0 @@ -/* -Copyright 2022 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 } from "testcafe"; -import createFixture from "../../helpers/createFixture/index.js"; -import cookies from "../../helpers/cookies.js"; -import { - compose, - orgMainConfigMain, - debugEnabled, -} from "../../helpers/constants/configParts/index.js"; -import { MAIN_IDENTITY_COOKIE_NAME } from "../../helpers/constants/cookies.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; -import createNetworkLogger from "../../helpers/networkLogger/index.js"; -import getResponseBody from "../../helpers/networkLogger/getResponseBody.js"; -import createConsoleLogger from "../../helpers/consoleLogger/index.js"; - -const debugEnabledConfig = compose(orgMainConfigMain, debugEnabled); -const networkLogger = createNetworkLogger(); - -createFixture({ - title: "C5287654: Cookies are set with sameSite=none", - requestHooks: [networkLogger.edgeEndpointLogs], -}); - -test.meta({ - ID: "C2581", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -test("Test C5287654: Cookies are set with sameSite=none", async () => { - const logger = await createConsoleLogger(); - const alloy = createAlloyProxy(); - await alloy.configure(debugEnabledConfig); - // this should get cookies - await logger.reset(); - await alloy.sendEvent(); - await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(1); - - // make sure we have an ecid - const identityCookieValue = await cookies.get(MAIN_IDENTITY_COOKIE_NAME); - await t.expect(identityCookieValue).ok("No identity cookie found."); - - // make sure the ecid was sent with sameSite = none - const response = JSON.parse( - getResponseBody(networkLogger.edgeEndpointLogs.requests[0]), - ); - - const stateStoreHandle = response.handle.find( - (handle) => handle.type === "state:store", - ); - const identityCookie = stateStoreHandle.payload.find((cookie) => - cookie.key.endsWith("identity"), - ); - await t.expect(identityCookie.attrs).ok(); - await t.expect(identityCookie.attrs.SameSite).eql("None"); - - const logs = await logger.info.getMessagesSinceReset(); - const setCookieAttributes = logs - .filter( - (message) => message.length === 3 && message[1] === "Setting cookie", - ) - .map((message) => message[2]) - .filter( - (cookieSettings) => cookieSettings.name === MAIN_IDENTITY_COOKIE_NAME, - ); - - await t.expect(setCookieAttributes.length).eql(1); - await t.expect(setCookieAttributes[0].sameSite).eql("none"); - await t.expect(setCookieAttributes[0].secure).eql(true); -}); diff --git a/packages/core/test/functional/specs/Identity/C5594865.js b/packages/core/test/functional/specs/Identity/C5594865.js deleted file mode 100644 index 29f5d219b..000000000 --- a/packages/core/test/functional/specs/Identity/C5594865.js +++ /dev/null @@ -1,66 +0,0 @@ -/* -Copyright 2022 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 } from "testcafe"; -import createFixture from "../../helpers/createFixture/index.js"; -import { SECONDARY_TEST_PAGE } from "../../helpers/constants/url.js"; -import { - compose, - orgMainConfigMain, - debugEnabled, - thirdPartyCookiesDisabled, -} from "../../helpers/constants/configParts/index.js"; -import createNetworkLogger from "../../helpers/networkLogger/index.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; -import getReturnedEcid from "../../helpers/networkLogger/getReturnedEcid.js"; - -// We disable third party cookies so that the domains don't share identities -// through the demdex cookies. -const config = compose( - orgMainConfigMain, - debugEnabled, - thirdPartyCookiesDisabled, -); - -const networkLogger = createNetworkLogger(); - -createFixture({ - title: - "C5594865: Identity can be maintained across domains via the adobe_mc query string parameter", - requestHooks: [networkLogger.edgeEndpointLogs], -}); - -test.meta({ - ID: "C5594865", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -test("C5594865: Identity can be maintained across domains via the adobe_mc query string parameter", async () => { - const alloy = createAlloyProxy(); - await alloy.configure(config); - await alloy.sendEvent({}); - const { url: newUrl } = await alloy.appendIdentityToUrl({ - url: SECONDARY_TEST_PAGE, - }); - - await t.navigateTo(newUrl); - await alloy.configure(config); - await alloy.sendEvent({}); - - const [originalEcid, newEcid] = - networkLogger.edgeEndpointLogs.requests.map(getReturnedEcid); - await t.expect(newEcid).eql(originalEcid); - - const { identity } = await alloy.getIdentity(); - await t.expect(identity.ECID).eql(originalEcid); -}); diff --git a/packages/core/test/functional/specs/Identity/C5594866.js b/packages/core/test/functional/specs/Identity/C5594866.js deleted file mode 100644 index 6e85318c4..000000000 --- a/packages/core/test/functional/specs/Identity/C5594866.js +++ /dev/null @@ -1,79 +0,0 @@ -/* -Copyright 2022 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 } from "testcafe"; -import createFixture from "../../helpers/createFixture/index.js"; -import { - compose, - orgMainConfigMain, - debugEnabled, - thirdPartyCookiesDisabled, - migrationDisabled, -} from "../../helpers/constants/configParts/index.js"; -import createNetworkLogger from "../../helpers/networkLogger/index.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; -import reloadPage from "../../helpers/reloadPage.js"; -import getReturnedEcid from "../../helpers/networkLogger/getReturnedEcid.js"; -import { TEST_PAGE, SECONDARY_TEST_PAGE } from "../../helpers/constants/url.js"; - -// We disable third party cookies so that the domains don't share identities -// through the demdex cookies. -const config = compose( - orgMainConfigMain, - thirdPartyCookiesDisabled, - debugEnabled, - migrationDisabled, -); - -const networkLogger = createNetworkLogger(); - -createFixture({ - title: - "C5594866: Identity can be changed via the adobe_mc query string parameter", - requestHooks: [networkLogger.edgeEndpointLogs], -}); - -test.meta({ - ID: "C5594866", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -test("C5594866: Identity can be changed via the adobe_mc query string parameter", async () => { - const alloy = createAlloyProxy(); - await alloy.configure(config); - // establish an identity cookie - await alloy.sendEvent({}); - - await t.navigateTo(SECONDARY_TEST_PAGE); - await alloy.configure(config); - await alloy.sendEvent({}); - const { url: newUrl } = await alloy.appendIdentityToUrl({ url: TEST_PAGE }); - - await t.navigateTo(newUrl); - await alloy.configure(config); - await alloy.sendEvent({}); - - await reloadPage(""); - await alloy.configure(config); - await alloy.sendEvent({}); - - const [originalEcid, secondaryPageEcid, newEcid, reloadedEcid] = - networkLogger.edgeEndpointLogs.requests.map(getReturnedEcid); - - await t.expect(originalEcid).notEql(secondaryPageEcid); - await t.expect(newEcid).eql(secondaryPageEcid); - await t.expect(reloadedEcid).eql(secondaryPageEcid); - - const { identity } = await alloy.getIdentity(); - await t.expect(identity.ECID).eql(secondaryPageEcid); -}); diff --git a/packages/core/test/functional/specs/Identity/C5594871.js b/packages/core/test/functional/specs/Identity/C5594871.js deleted file mode 100644 index a5e4417da..000000000 --- a/packages/core/test/functional/specs/Identity/C5594871.js +++ /dev/null @@ -1,47 +0,0 @@ -/* -Copyright 2022 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 } from "testcafe"; -import createFixture from "../../helpers/createFixture/index.js"; -import { - compose, - orgMainConfigMain, - debugEnabled, -} from "../../helpers/constants/configParts/index.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; -import createRandomEcid from "../../helpers/createRandomEcid.js"; -import { TEST_PAGE as TEST_PAGE_URL } from "../../helpers/constants/url.js"; -import createAdobeMC from "../../helpers/createAdobeMC.js"; - -const config = compose(orgMainConfigMain, debugEnabled); - -const id = createRandomEcid(); -const adobemc = createAdobeMC({ id }); - -createFixture({ - url: `${TEST_PAGE_URL}?adobe_mc=${adobemc}`, - title: "C5594871: getIdentity works with adobe_mc query string parameter", - requestHooks: [], -}); - -test.meta({ - ID: "C5594871", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -test("C5594871: getIdentity works with adobe_mc query string parameter", async () => { - const alloy = createAlloyProxy(); - await alloy.configure(config); - const ecid = await alloy.getIdentity(); - await t.expect(ecid.identity.ECID).eql(id); -}); diff --git a/packages/core/test/functional/specs/Identity/C5594872.js b/packages/core/test/functional/specs/Identity/C5594872.js deleted file mode 100644 index 80875c2c7..000000000 --- a/packages/core/test/functional/specs/Identity/C5594872.js +++ /dev/null @@ -1,54 +0,0 @@ -/* -Copyright 2022 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 } from "testcafe"; -import createFixture from "../../helpers/createFixture/index.js"; -import { TEST_PAGE as TEST_PAGE_URL } from "../../helpers/constants/url.js"; -import { - compose, - orgMainConfigMain, - debugEnabled, -} from "../../helpers/constants/configParts/index.js"; -import createNetworkLogger from "../../helpers/networkLogger/index.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; -import createRandomEcid from "../../helpers/createRandomEcid.js"; -import getReturnedEcid from "../../helpers/networkLogger/getReturnedEcid.js"; -import createAdobeMC from "../../helpers/createAdobeMC.js"; - -const config = compose(orgMainConfigMain, debugEnabled); - -const networkLogger = createNetworkLogger(); - -const id = createRandomEcid(); -// TTL is 5 minutes (300 seconds), but use 400 to account for differences in server time. -const timestamp = new Date().getTime() / 1000 - 400; -const adobemc = createAdobeMC({ timestamp, id }); - -createFixture({ - url: `${TEST_PAGE_URL}?adobe_mc=${adobemc}`, - title: "C5594872: An expired adobe_mc query string parameter is not used", - requestHooks: [networkLogger.edgeEndpointLogs], -}); - -test.meta({ - ID: "C5594872", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -test("C5594872: An expired adobe_mc query string parameter is not used", async () => { - const alloy = createAlloyProxy(); - await alloy.configure(config); - await alloy.sendEvent({}); - const ecid = getReturnedEcid(networkLogger.edgeEndpointLogs.requests[0]); - await t.expect(ecid).notEql(id); -}); diff --git a/packages/core/test/functional/specs/Identity/C5598188.js b/packages/core/test/functional/specs/Identity/C5598188.js deleted file mode 100644 index 76ed6a035..000000000 --- a/packages/core/test/functional/specs/Identity/C5598188.js +++ /dev/null @@ -1,46 +0,0 @@ -/* -Copyright 2022 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 { - compose, - orgMainConfigMain, - debugEnabled, -} from "../../helpers/constants/configParts/index.js"; -import { TEST_PAGE } from "../../helpers/constants/url.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; -import createFixture from "../../helpers/createFixture/index.js"; -import createConsoleLogger from "../../helpers/consoleLogger/index.js"; - -const config = compose(orgMainConfigMain, debugEnabled, { - orgId: "invalid-org-id@Adobe", -}); - -createFixture({ - url: TEST_PAGE, - title: - "C5598188: Informative error messages are given when an identity cookie fails to be set", -}); - -test.meta({ - ID: "C5598188", - SEVERTIY: "P0", - TEST_RUN: "Regression", -}); - -test("C5598188: Informative error message given when using an invalid orgID", async () => { - const logger = await createConsoleLogger(); - const validAlloy = createAlloyProxy(); - await validAlloy.configure(config); - await validAlloy.sendEvent({}); - await logger.warn.expectMessageMatching(/Identity cookie not found/); - await logger.warn.expectMessageMatching(/invalid-org-id/); -}); diff --git a/packages/core/test/functional/specs/Identity/C6842980.js b/packages/core/test/functional/specs/Identity/C6842980.js deleted file mode 100644 index f8d86e520..000000000 --- a/packages/core/test/functional/specs/Identity/C6842980.js +++ /dev/null @@ -1,77 +0,0 @@ -/* -Copyright 2022 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 } from "testcafe"; -import { - compose, - orgMainConfigMain, - debugEnabled, - thirdPartyCookiesDisabled, - migrationDisabled, -} from "../../helpers/constants/configParts/index.js"; -import { TEST_PAGE } from "../../helpers/constants/url.js"; -import createNetworkLogger from "../../helpers/networkLogger/index.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; -import getReturnedEcid from "../../helpers/networkLogger/getReturnedEcid.js"; -import createFixture from "../../helpers/createFixture/index.js"; -import reloadPage from "../../helpers/reloadPage.js"; -import cookies from "../../helpers/cookies.js"; -import { MAIN_IDENTITY_COOKIE_NAME } from "../../helpers/constants/cookies.js"; - -const networkLogger = createNetworkLogger(); -const config = compose( - orgMainConfigMain, - debugEnabled, - thirdPartyCookiesDisabled, - migrationDisabled, -); - -createFixture({ - url: TEST_PAGE, - title: "C6842980: FPID from the identityMap is used to generate an ECID", - requestHooks: [networkLogger.edgeEndpointLogs], -}); - -test.meta({ - ID: "C6842980", - SEVERTIY: "P0", - TEST_RUN: "Regression", -}); - -const fpid = { - xdm: { - identityMap: { - FPID: [ - { - id: "UUID", - }, - ], - }, - }, -}; - -test("C6842980: FPID from the identityMap generates ECID", async () => { - const alloy = createAlloyProxy(); - - await alloy.configure(config); - await alloy.sendEvent(fpid); - const ecid = getReturnedEcid(networkLogger.edgeEndpointLogs.requests[0]); - - await reloadPage(); - await cookies.remove(MAIN_IDENTITY_COOKIE_NAME); - await alloy.configure(config); - await alloy.sendEvent(fpid); - const ecidCompare = getReturnedEcid( - networkLogger.edgeEndpointLogs.requests[1], - ); - await t.expect(ecid).eql(ecidCompare); -}); diff --git a/packages/core/test/functional/specs/Identity/C6842981.js b/packages/core/test/functional/specs/Identity/C6842981.js deleted file mode 100644 index 68461f2e2..000000000 --- a/packages/core/test/functional/specs/Identity/C6842981.js +++ /dev/null @@ -1,90 +0,0 @@ -/* -Copyright 2022 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 } from "testcafe"; -import { v4 as uuidv4 } from "uuid"; -import { - compose, - orgMainConfigMain, - debugEnabled, - migrationDisabled, - thirdPartyCookiesDisabled, - edgeDomainFirstParty, -} from "../../helpers/constants/configParts/index.js"; -import { TEST_PAGE } from "../../helpers/constants/url.js"; -import createNetworkLogger from "../../helpers/networkLogger/index.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; -import getReturnedEcid from "../../helpers/networkLogger/getReturnedEcid.js"; -import createFixture from "../../helpers/createFixture/index.js"; -import reloadPage from "../../helpers/reloadPage.js"; -import cookies from "../../helpers/cookies.js"; -import { MAIN_IDENTITY_COOKIE_NAME } from "../../helpers/constants/cookies.js"; - -const networkLogger = createNetworkLogger(); -const config = compose( - orgMainConfigMain, - debugEnabled, - migrationDisabled, - thirdPartyCookiesDisabled, - edgeDomainFirstParty, -); - -createFixture({ - url: TEST_PAGE, - title: "C6842981: FPID from a custom FPID cookie is used to generate an ECID", - requestHooks: [networkLogger.edgeEndpointLogs], -}); - -test.meta({ - ID: "C6842981", - SEVERTIY: "P0", - TEST_RUN: "Regression", -}); - -test("C6842981: FPID from a custom FPID cookie generates an ECID", async () => { - const value = uuidv4(); - - // TestCafe uses Native automation when running tests in Chrome. For this case, the cookie need - // to be set to `.allioyio.com` and not `alloyio.com`. For Firefox, TestCase uses a reverse proxy - // to automate browsers. The emulation is not fully compatible with Native automation. So we need - // to set the cookie also on `alloyio.com` to make the test to pass on other browsers. - await t.setCookies({ - name: "myFPID", - value, - domain: ".alloyio.com", - path: "/", - }); - - await t.setCookies({ - name: "myFPID", - value, - domain: "alloyio.com", - path: "/", - }); - - const alloy = createAlloyProxy(); - await alloy.configure(config); - await alloy.sendEvent(); - - const ecid = getReturnedEcid(networkLogger.edgeEndpointLogs.requests[0]); - await reloadPage(); - - await cookies.remove(MAIN_IDENTITY_COOKIE_NAME); - - await alloy.configure(config); - await alloy.sendEvent(); - - const ecidCompare = getReturnedEcid( - networkLogger.edgeEndpointLogs.requests[1], - ); - await t.expect(ecid).eql(ecidCompare); -}); diff --git a/packages/core/test/functional/specs/Identity/C6842982.js b/packages/core/test/functional/specs/Identity/C6842982.js deleted file mode 100644 index aad42e755..000000000 --- a/packages/core/test/functional/specs/Identity/C6842982.js +++ /dev/null @@ -1,72 +0,0 @@ -/* -Copyright 2022 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 } from "testcafe"; -import { - compose, - orgMainConfigMain, - debugEnabled, - thirdPartyCookiesDisabled, - migrationDisabled, -} from "../../helpers/constants/configParts/index.js"; -import { TEST_PAGE } from "../../helpers/constants/url.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; -import createFixture from "../../helpers/createFixture/index.js"; -import createNetworkLogger from "../../helpers/networkLogger/index.js"; -import getReturnedEcid from "../../helpers/networkLogger/getReturnedEcid.js"; - -const networkLogger = createNetworkLogger(); -const config = compose( - orgMainConfigMain, - debugEnabled, - thirdPartyCookiesDisabled, - migrationDisabled, -); - -createFixture({ - url: TEST_PAGE, - title: - "C6842982: existing identity cookie takes precedence over an FPID provided in the identity map.", - requestHooks: [networkLogger.edgeEndpointLogs], -}); - -test.meta({ - ID: "C6842982", - SEVERTIY: "P0", - TEST_RUN: "Regression", -}); - -const fpid = { - xdm: { - identityMap: { - FPID: [ - { - id: "UUID", - }, - ], - }, - }, -}; - -test("C6842982: identity cookie takes precedence over an FPID", async () => { - const alloy = createAlloyProxy(); - await alloy.configure(config); - await alloy.sendEvent(); - const ecid = await getReturnedEcid( - networkLogger.edgeEndpointLogs.requests[0], - ); - await alloy.sendEvent(fpid); - const ecidCompare = getReturnedEcid( - networkLogger.edgeEndpointLogs.requests[1], - ); - await t.expect(ecid).eql(ecidCompare); -}); diff --git a/packages/core/test/functional/specs/Install SDK/C1338399.js b/packages/core/test/functional/specs/Install SDK/C1338399.js deleted file mode 100644 index df1e38415..000000000 --- a/packages/core/test/functional/specs/Install SDK/C1338399.js +++ /dev/null @@ -1,52 +0,0 @@ -/* -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 createNetworkLogger from "../../helpers/networkLogger/index.js"; -import { - compose, - orgMainConfigMain, - debugEnabled, - migrationDisabled, -} from "../../helpers/constants/configParts/index.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; - -const mainConfig = compose(orgMainConfigMain, debugEnabled, migrationDisabled); - -const networkLogger = createNetworkLogger(); - -createFixture({ - title: "C1338399: Use SDK from NPM entry point", - includeAlloyLibrary: false, - includeNpmLibrary: true, - requestHooks: [networkLogger.edgeEndpointLogs], -}); - -const createAlloyInstance = ClientFunction(() => { - window.npmLibraryAlloy = window.alloyCreateInstance({ - name: "npmLibraryAlloy", - }); -}); - -test.meta({ - ID: "C1338399: Use SDK from NPM entry point", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -test("C1338399: Use SDK from NPM entry point", async () => { - await createAlloyInstance(); - const alloy = createAlloyProxy("npmLibraryAlloy"); - await alloy.configure(mainConfig); - await alloy.sendEvent(); - await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(1); -}); diff --git a/packages/core/test/functional/specs/Install SDK/C2560.js b/packages/core/test/functional/specs/Install SDK/C2560.js deleted file mode 100644 index 20f1da8b9..000000000 --- a/packages/core/test/functional/specs/Install SDK/C2560.js +++ /dev/null @@ -1,30 +0,0 @@ -/* -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"; - -const getAlloyFunction = ClientFunction(() => !!window.alloy); - -createFixture({ - title: "C2560: Global function named alloy is accessible.", -}); - -test.meta({ - ID: "C2560", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -test("Test C2560: The global function named alloy is accessible.", async () => { - const alloy = await getAlloyFunction(); - await t.expect(alloy).ok(); -}); diff --git a/packages/core/test/functional/specs/Install SDK/C2579.js b/packages/core/test/functional/specs/Install SDK/C2579.js deleted file mode 100644 index c7a72c90e..000000000 --- a/packages/core/test/functional/specs/Install SDK/C2579.js +++ /dev/null @@ -1,85 +0,0 @@ -/* -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 { RequestLogger, t } from "testcafe"; -import createFixture from "../../helpers/createFixture/index.js"; -import { - compose, - orgMainConfigMain, - orgAltConfigAlt, - debugEnabled, - migrationDisabled, -} from "../../helpers/constants/configParts/index.js"; -import DATASTREAM_ID from "../../helpers/constants/datastreamId.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; - -const mainConfig = compose(orgMainConfigMain, debugEnabled, migrationDisabled); -const altConfig = compose(orgAltConfigAlt, debugEnabled, migrationDisabled); - -const networkLoggerConfig = { - logRequestBody: true, - stringifyRequestBody: true, -}; -const networkLogger1 = RequestLogger( - /v1\/(interact|collect)\?configId=9999999/, - networkLoggerConfig, -); - -const networkLogger2 = RequestLogger( - new RegExp(`v1\\/(interact|collect)\\?configId=${DATASTREAM_ID}`), - networkLoggerConfig, -); - -createFixture({ - title: "C2579: Isolates multiple SDK instances", - requestHooks: [networkLogger1, networkLogger2], -}); - -test.meta({ - ID: "C2579", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -const getIdentityCookieValue = (request) => { - const payload = JSON.parse(request.request.body); - if (!payload.meta.state.entries) { - return undefined; - } - const identityEntry = payload.meta.state.entries.find((entry) => - entry.key.includes("_identity"), - ); - return identityEntry.value; -}; - -test("Test C2579: Separate ECIDs are used for multiple SDK instances.", async () => { - const instance1 = createAlloyProxy(); - const instance2 = createAlloyProxy("instance2"); - await instance1.configure(altConfig); - await instance2.configure(mainConfig); - await instance1.sendEvent(); - await instance2.sendEvent(); - await instance1.sendEvent(); - await instance2.sendEvent(); - - await t.expect(networkLogger1.requests.length).eql(2); - await t.expect(networkLogger2.requests.length).eql(2); - const id1a = getIdentityCookieValue(networkLogger1.requests[0]); - const id1b = getIdentityCookieValue(networkLogger1.requests[1]); - const id2a = getIdentityCookieValue(networkLogger2.requests[0]); - const id2b = getIdentityCookieValue(networkLogger2.requests[1]); - - await t.expect(id1a).eql(undefined); - await t.expect(id1b).notEql(undefined); - await t.expect(id2a).eql(undefined); - await t.expect(id2b).notEql(undefined); - await t.expect(id1b).notEql(id2b); -}); diff --git a/packages/core/test/functional/specs/LibraryInfo/C2589.js b/packages/core/test/functional/specs/LibraryInfo/C2589.js deleted file mode 100644 index bc84e6a22..000000000 --- a/packages/core/test/functional/specs/LibraryInfo/C2589.js +++ /dev/null @@ -1,125 +0,0 @@ -/* -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 { ClientFunction, t } from "testcafe"; -import createFixture from "../../helpers/createFixture/index.js"; - -import { - compose, - debugEnabled, - orgMainConfigMain, -} from "../../helpers/constants/configParts/index.js"; - -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; -import { - ADOBE_JOURNEY_OPTIMIZER, - ADOBE_TARGET, -} from "../../../../src/constants/decisionProvider.js"; -import { - ALWAYS, - NEVER, -} from "../../../../src/constants/propositionInteractionType.js"; - -const debugEnabledConfig = compose(orgMainConfigMain, debugEnabled, { - onBeforeEventSend: () => {}, -}); - -createFixture({ - title: "C2589: getLibraryInfo command returns library information", -}); - -test.meta({ - ID: "C2589", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -test("C2589: getLibraryInfo command returns library information.", async () => { - const currentVersion = process.env.npm_package_version; - const currentCommand = [ - "appendIdentityToUrl", - "applyPropositions", - "applyResponse", - "configure", - "createEventMergeId", - "createMediaSession", - "evaluateRulesets", - "getIdentity", - "getLibraryInfo", - "getMediaAnalyticsTracker", - "sendEvent", - "sendMediaEvent", - "sendPushSubscription", - "setConsent", - "setDebug", - "subscribeRulesetItems", - ]; - const currentConfigs = { - clickCollectionEnabled: true, - clickCollection: { - downloadLinkEnabled: true, - eventGroupingEnabled: false, - externalLinkEnabled: true, - internalLinkEnabled: true, - sessionStorageEnabled: false, - }, - context: ["web", "device", "environment", "placeContext"], - debugEnabled: true, - defaultConsent: "in", - downloadLinkQualifier: - "\\.(exe|zip|wav|mp3|mov|mpg|avi|wmv|pdf|doc|docx|xls|xlsx|ppt|pptx)$", - datastreamId: "bc1a10e0-aee4-4e0e-ac5b-cdbb9abbec83", - edgeDomain: "edge.adobedc.net", - idMigrationEnabled: true, - onBeforeEventSend: "() => {}", - orgId: "5BFE274A5F6980A50A495C08@AdobeOrg", - thirdPartyCookiesEnabled: true, - targetMigrationEnabled: false, - personalizationStorageEnabled: false, - autoCollectPropositionInteractions: { - [ADOBE_JOURNEY_OPTIMIZER]: ALWAYS, - [ADOBE_TARGET]: NEVER, - }, - }; - - const alloy = createAlloyProxy(); - await alloy.configure(debugEnabledConfig); - const { libraryInfo } = await alloy.getLibraryInfo(); - delete libraryInfo.configs.edgeBasePath; - await t.expect(libraryInfo.version).eql(currentVersion); - await t.expect(libraryInfo.commands).eql(currentCommand); - await t.expect(libraryInfo.configs).eql(currentConfigs); -}); - -test("C2589: getLibraryInfo correctly serializes functions in the config", async () => { - const alloy = createAlloyProxy(); - await alloy.configure(debugEnabledConfig); - const { libraryInfo } = await alloy.getLibraryInfo(); - await t.expect(typeof libraryInfo.configs.onBeforeEventSend).eql("string"); -}); - -test("C2589: libraryInfo can be marshaled to postMessage", async () => { - const instanceName = "alloy"; - const alloy = createAlloyProxy(instanceName); - await alloy.configure(debugEnabledConfig); - const postLibraryInfo = ClientFunction( - () => { - return window[instanceName]("getLibraryInfo").then(({ libraryInfo }) => { - window.postMessage(libraryInfo, "*"); - }); - }, - { dependencies: { instanceName } }, - ); - const result = await postLibraryInfo(); - // This is really just asserting that we got this far. If libraryInfo cannot be - // marshaled, postLibraryInfo() will throw an exception about cloning functions. - await t.expect(result).notOk("getLibraryInfo can be marshaled successfully"); -}); diff --git a/packages/core/test/functional/specs/Location Hints/C6589015.js b/packages/core/test/functional/specs/Location Hints/C6589015.js deleted file mode 100644 index bc5413262..000000000 --- a/packages/core/test/functional/specs/Location Hints/C6589015.js +++ /dev/null @@ -1,61 +0,0 @@ -/* -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 } from "testcafe"; -import createNetworkLogger from "../../helpers/networkLogger/index.js"; -import cookies from "../../helpers/cookies.js"; -import createFixture from "../../helpers/createFixture/index.js"; -import { - compose, - orgMainConfigMain, - thirdPartyCookiesDisabled, - debugEnabled, -} from "../../helpers/constants/configParts/index.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; -import { MAIN_CLUSTER_COOKIE_NAME } from "../../helpers/constants/cookies.js"; - -const networkLogger = createNetworkLogger(); -const config = compose( - orgMainConfigMain, - debugEnabled, - thirdPartyCookiesDisabled, -); - -createFixture({ - title: - "C6589015: The Experience Edge location hint is used on the second request.", - requestHooks: [networkLogger.edgeEndpointLogs], -}); - -test.meta({ - ID: "C6589015", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -test("Test C6589015: The Experience Edge location hint is used on the second request.", async () => { - const alloy = createAlloyProxy(); - await alloy.configure(config); - await alloy.sendEvent({}); - - const locationHint = await cookies.get(MAIN_CLUSTER_COOKIE_NAME); - await t.expect(locationHint).ok(); - - await alloy.sendEvent({}); - - const urls = networkLogger.edgeEndpointLogs.requests.map( - (r) => r.request.url, - ); - await t.expect(urls[0]).match(/^https:\/\/[^/]+\/[^/]+\/v1\/interact/); - await t - .expect(urls[1]) - .match(new RegExp(`^https://[^/]+/[^/]+/${locationHint}/v1/interact`)); -}); diff --git a/packages/core/test/functional/specs/Location Hints/C6944931.js b/packages/core/test/functional/specs/Location Hints/C6944931.js deleted file mode 100644 index 5b2f1473a..000000000 --- a/packages/core/test/functional/specs/Location Hints/C6944931.js +++ /dev/null @@ -1,65 +0,0 @@ -/* -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 } from "testcafe"; -import createNetworkLogger from "../../helpers/networkLogger/index.js"; -import cookies from "../../helpers/cookies.js"; -import createFixture from "../../helpers/createFixture/index.js"; -import { - compose, - orgMainConfigMain, - thirdPartyCookiesDisabled, - debugEnabled, -} from "../../helpers/constants/configParts/index.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; -import { MAIN_CLUSTER_COOKIE_NAME } from "../../helpers/constants/cookies.js"; - -const networkLogger = createNetworkLogger(); -const config = compose( - orgMainConfigMain, - debugEnabled, - thirdPartyCookiesDisabled, -); - -createFixture({ - title: "C6944931: The legacy Adobe Target location hint is used.", - requestHooks: [networkLogger.edgeEndpointLogs], -}); - -test.meta({ - ID: "C6944931", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -test("Test C6944931: The legacy Adobe Target location hint is used.", async () => { - // 38 = singapore, Konductor region ID 3 - await t.setCookies({ - name: "mboxEdgeCluster", - value: "38", - domain: "alloyio.com", - path: "/", - }); - const alloy = createAlloyProxy(); - await alloy.configure(config); - await alloy.sendEvent({}); - - const locationHint = await cookies.get(MAIN_CLUSTER_COOKIE_NAME); - await t.expect(locationHint).eql("sgp3"); - - await alloy.sendEvent({}); - - const urls = networkLogger.edgeEndpointLogs.requests.map( - (r) => r.request.url, - ); - await t.expect(urls[0]).match(/^https:\/\/[^/]+\/[^/]+\/t38\/v1\/interact/); - await t.expect(urls[1]).match(/^https:\/\/[^/]+\/[^/]+\/sgp3\/v1\/interact/); -}); diff --git a/packages/core/test/functional/specs/Logging/C2583.js b/packages/core/test/functional/specs/Logging/C2583.js deleted file mode 100644 index e9dbd6b86..000000000 --- a/packages/core/test/functional/specs/Logging/C2583.js +++ /dev/null @@ -1,57 +0,0 @@ -/* -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 createFixture from "../../helpers/createFixture/index.js"; -import { - compose, - orgMainConfigMain, - debugEnabled, - debugDisabled, -} from "../../helpers/constants/configParts/index.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; - -const debugEnabledConfig = compose(orgMainConfigMain, debugEnabled); - -const debugDisabledConfig = compose(orgMainConfigMain, debugDisabled); - -createFixture({ - title: "C2583: Toggle logging through configuration", -}); - -test.meta({ - ID: "C2583", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -test("Test C2583: Set the log option to true. Load the page. Execute a sendEvent command.", async (t) => { - const alloy = createAlloyProxy(); - await alloy.configure(debugEnabledConfig); - await alloy.sendEvent(); - - const { info } = await t.getBrowserConsoleMessages(); - - await t.expect(info).match(/\[alloy] Executing sendEvent command./); -}); - -test("Test C2583: Set the log option in the configuration to false. Refresh the browser. Execute a sendEvent command.", async (t) => { - const alloy = createAlloyProxy(); - await alloy.configure(debugDisabledConfig); - await alloy.sendEvent(); - - const { info } = await t.getBrowserConsoleMessages(); - - await t.expect(info).notContains("Executing sendEvent command."); - - await alloy.sendEvent(); - - await t.expect(info).notContains("Executing sendEvent command."); -}); diff --git a/packages/core/test/functional/specs/Logging/C2584.js b/packages/core/test/functional/specs/Logging/C2584.js deleted file mode 100644 index 3d49d7438..000000000 --- a/packages/core/test/functional/specs/Logging/C2584.js +++ /dev/null @@ -1,42 +0,0 @@ -/* -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 createConsoleLogger from "../../helpers/consoleLogger/index.js"; -import createFixture from "../../helpers/createFixture/index.js"; -import { orgMainConfigMain } from "../../helpers/constants/configParts/index.js"; -import reloadPage from "../../helpers/reloadPage.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; - -createFixture({ - title: "C2584: Toggle logging through setDebug command", -}); - -test.meta({ - ID: "C2584", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -test("Test C2584: setDebug command with enable: true. getLibraryInfo. refresh. toggle and repeat.", async () => { - const logger = await createConsoleLogger(); - const alloy = createAlloyProxy(); - await alloy.configure(orgMainConfigMain); - await alloy.setDebug({ enabled: true }); - await alloy.getLibraryInfo(); - await logger.info.expectMessageMatching(/Executing getLibraryInfo command/); - - await reloadPage(); - await alloy.configure(orgMainConfigMain); - await alloy.setDebug({ enabled: false }); - await logger.reset(); - await alloy.getLibraryInfo(); - await logger.info.expectNoMessages(); -}); diff --git a/packages/core/test/functional/specs/Logging/C2586.js b/packages/core/test/functional/specs/Logging/C2586.js deleted file mode 100644 index 1187f04b9..000000000 --- a/packages/core/test/functional/specs/Logging/C2586.js +++ /dev/null @@ -1,35 +0,0 @@ -/* -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 createFixture from "../../helpers/createFixture/index.js"; -import { TEST_PAGE as TEST_PAGE_URL } from "../../helpers/constants/url.js"; -import { orgMainConfigMain } from "../../helpers/constants/configParts/index.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; - -createFixture({ - title: "C2586: Toggle logging through the querystring parameter.", - url: `${TEST_PAGE_URL}?alloy_debug=true`, -}); - -test.meta({ - ID: "C2586", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -test("Test C2586: Toggle logging through the querystring parameter.", async (t) => { - const alloy = createAlloyProxy(); - await alloy.configure(orgMainConfigMain); - await alloy.getLibraryInfo(); - - const { info } = await t.getBrowserConsoleMessages(); - await t.expect(info).match(/Executing getLibraryInfo command/); -}); diff --git a/packages/core/test/functional/specs/Logging/C532204.js b/packages/core/test/functional/specs/Logging/C532204.js deleted file mode 100644 index ac7cea20d..000000000 --- a/packages/core/test/functional/specs/Logging/C532204.js +++ /dev/null @@ -1,58 +0,0 @@ -/* -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 { ClientFunction } from "testcafe"; -import createFixture from "../../helpers/createFixture/index.js"; -import { - compose, - orgMainConfigMain, - debugEnabled, -} from "../../helpers/constants/configParts/index.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; - -const debugEnabledConfig = compose(orgMainConfigMain, debugEnabled); - -/* - * Some pages will redefine the console logging methods with implementations - * that aren't as forgiving as the built in logger. We ran into this issue - * on a Shopify site with a redefined logger. This test runs through some basic - * scenarios and makes sure the logged objects can be stringified - */ -createFixture({ - title: "C532204: Logged objects can be stringified", -}); - -test.meta({ - ID: "C532204", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -const setupLogger = ClientFunction(() => { - ["log", "info", "warn", "error"].forEach((methodName) => { - // eslint-disable-next-line no-console - const origConsoleMethod = console[methodName]; - // eslint-disable-next-line no-console - console[methodName] = (...args) => { - args.forEach((arg) => { - String(arg); - }); - origConsoleMethod.apply(console, args); - }; - }); -}); - -test("Test C532204: Logged objects can be stringified", async () => { - await setupLogger(); - const alloy = createAlloyProxy(); - await alloy.configure(debugEnabledConfig); - await alloy.sendEvent(); -}); diff --git a/packages/core/test/functional/specs/MediaCollection/MA1.js b/packages/core/test/functional/specs/MediaCollection/MA1.js deleted file mode 100644 index ddd3636ea..000000000 --- a/packages/core/test/functional/specs/MediaCollection/MA1.js +++ /dev/null @@ -1,302 +0,0 @@ -/* -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 { t } from "testcafe"; -import createNetworkLogger from "../../helpers/networkLogger/index.js"; -import { responseStatus } from "../../helpers/assertions/index.js"; -import createFixture from "../../helpers/createFixture/index.js"; -import { compose } from "../../helpers/constants/configParts/index.js"; -import getResponseBody from "../../helpers/networkLogger/getResponseBody.js"; -import createResponse from "../../helpers/createResponse.js"; -import { TEST_PAGE as TEST_PAGE_URL } from "../../helpers/constants/url.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; -import orgMediaConfig from "../../helpers/constants/configParts/orgMediaConfig.js"; -import streamingMedia from "../../helpers/constants/configParts/streamingMedia.js"; -import { sleep } from "../Migration/helper.js"; - -const networkLogger = createNetworkLogger(); -const config = compose(orgMediaConfig, streamingMedia); -createFixture({ - title: "Streaming media in automatic mode.", - url: TEST_PAGE_URL, - requestHooks: [ - networkLogger.edgeEndpointLogs, - networkLogger.mediaPauseEndpointLogs, - networkLogger.mediaPlayEndpointLogs, - networkLogger.chapterStartEndpointLogs, - networkLogger.pingEndpointLogs, - networkLogger.chapterCompleteEndpointLogs, - networkLogger.chapterSkipEndpointLogs, - networkLogger.adStartEndpointLogs, - networkLogger.adBreakStartEndpointLogs, - networkLogger.adBreakCompleteEndpointLogs, - networkLogger.adSkipEndpointLogs, - networkLogger.adCompleteEndpointLogs, - networkLogger.errorEndpointLogs, - networkLogger.sessionCompleteEndpointLogs, - networkLogger.sessionEndEndpointLogs, - networkLogger.statesUpdateEndpointLogs, - networkLogger.bitrateChangeEndpointLogs, - ], -}); - -test.meta({ - ID: "MA1", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); -const assertSessionStartedInAutoPingMode = async (alloy) => { - const sessionPromise = await alloy.createMediaSession({ - playerId: "player1", - xdm: { - mediaCollection: { - sessionDetails: { - length: 60, - contentType: "VOD", - name: "test name of the video", - }, - }, - }, - getPlayerDetails: () => { - return { - playhead: 3, - qoeDataDetails: { - bitrate: 1, - droppedFrames: 2, - framesPerSecond: 3, - timeToStart: 4, - }, - }; - }, - }); - await responseStatus(networkLogger.edgeEndpointLogs.requests, [200, 207]); - await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(1); - - const createSession = networkLogger.edgeEndpointLogs.requests[0]; - const requestBody = JSON.parse(createSession.request.body); - await t.expect(requestBody.events[0].xdm.eventType).eql("media.sessionStart"); - await t.expect(requestBody.events[0].xdm.mediaCollection.playhead).eql(3); - const response = JSON.parse( - getResponseBody(networkLogger.edgeEndpointLogs.requests[0]), - ); - const mediaCollectionPayload = createResponse({ - content: response, - }).getPayloadsByType("media-analytics:new-session"); - - await t - .expect(mediaCollectionPayload[0].sessionId) - .eql(sessionPromise.sessionId); - - return sessionPromise; -}; -const assertPingsSent = async (sessionId) => { - const pingEventRequest = networkLogger.pingEndpointLogs.requests[0]; - const pingEvent = JSON.parse(pingEventRequest.request.body).events[0]; - await t.expect(pingEvent.xdm.mediaCollection.sessionID).eql(sessionId); - await t.expect(pingEvent.xdm.eventType).eql("media.ping"); -}; -const assertPingsNotSentWhenSessionClosed = async (alloy) => { - await alloy.sendMediaEvent({ - playerId: "player1", - xdm: { - eventType: "media.sessionComplete", - }, - }); - await sleep(10000); - - const secondPingEventRequest = networkLogger.pingEndpointLogs.requests[2]; - await t.expect(secondPingEventRequest).eql(undefined); -}; -const sendMediaEvent = async ( - alloy, - eventType, - sessionId, - additionalData = {}, -) => { - await alloy.sendMediaEvent({ - playerId: "player1", - xdm: { - eventType, - mediaCollection: { - ...additionalData, - }, - }, - }); -}; - -const assertEventIsSent = async (endpointLogs, eventType, sessionId) => { - const eventRequest = endpointLogs.requests[0]; - await responseStatus(endpointLogs.requests, 204); - - const event = JSON.parse(eventRequest.request.body).events[0]; - await t.expect(event.xdm.mediaCollection.playhead).eql(3); - await t.expect(event.xdm.mediaCollection.sessionID).eql(sessionId); - await t.expect(event.xdm.eventType).eql(eventType); -}; - -test("Test that MC component sends pings, augment the events with playhead and session", async () => { - const alloy = createAlloyProxy(); - await alloy.configure(config); - const { sessionId } = await assertSessionStartedInAutoPingMode(alloy); - await sleep(11000); - await assertPingsSent(sessionId); - - // play event - await sendMediaEvent(alloy, "media.play", sessionId); - await assertEventIsSent( - networkLogger.mediaPlayEndpointLogs, - "media.play", - sessionId, - ); - - // pause event - await sendMediaEvent(alloy, "media.pauseStart", sessionId); - await assertEventIsSent( - networkLogger.mediaPauseEndpointLogs, - "media.pauseStart", - sessionId, - ); - - // chapter start event - await sendMediaEvent(alloy, "media.chapterStart", sessionId, { - chapterDetails: { - friendlyName: "Chapter 1", - length: 10, - index: 1, - offset: 0, - }, - }); - await assertEventIsSent( - networkLogger.chapterStartEndpointLogs, - "media.chapterStart", - sessionId, - ); - - await sendMediaEvent(alloy, "media.chapterComplete", sessionId); - await assertEventIsSent( - networkLogger.chapterCompleteEndpointLogs, - "media.chapterComplete", - sessionId, - ); - - await sendMediaEvent(alloy, "media.chapterSkip", sessionId); - await assertEventIsSent( - networkLogger.chapterSkipEndpointLogs, - "media.chapterSkip", - sessionId, - ); - - await sendMediaEvent(alloy, "media.adBreakStart", sessionId, { - advertisingPodDetails: { - friendlyName: "Mid-roll", - offset: 0, - index: 1, - }, - }); - await assertEventIsSent( - networkLogger.adBreakStartEndpointLogs, - "media.adBreakStart", - sessionId, - ); - - await sendMediaEvent(alloy, "media.adStart", sessionId, { - advertisingDetails: { - friendlyName: "Ad 1", - name: "/uri-reference/001", - length: 10, - advertiser: "Adobe Marketing", - campaignID: "Adobe Analytics", - creativeID: "creativeID", - creativeURL: "https://creativeurl.com", - placementID: "placementID", - siteID: "siteID", - podPosition: 11, - playerName: "HTML5 player", - }, - }); - await assertEventIsSent( - networkLogger.adStartEndpointLogs, - "media.adStart", - sessionId, - ); - - await sendMediaEvent(alloy, "media.adComplete", sessionId); - await assertEventIsSent( - networkLogger.adCompleteEndpointLogs, - "media.adComplete", - sessionId, - ); - - await sendMediaEvent(alloy, "media.adBreakComplete", sessionId); - await assertEventIsSent( - networkLogger.adBreakCompleteEndpointLogs, - "media.adBreakComplete", - sessionId, - ); - - await sendMediaEvent(alloy, "media.adSkip", sessionId); - await assertEventIsSent( - networkLogger.adSkipEndpointLogs, - "media.adSkip", - sessionId, - ); - - await sendMediaEvent(alloy, "media.error", sessionId, { - errorDetails: { - name: "test-buffer-start", - source: "player", - }, - }); - await assertEventIsSent( - networkLogger.errorEndpointLogs, - "media.error", - sessionId, - ); - - await sendMediaEvent(alloy, "media.bitrateChange", sessionId, { - qoeDataDetails: { - framesPerSecond: 1, - bitrate: 35000, - droppedFrames: 30, - timeToStart: 1364, - }, - }); - await assertEventIsSent( - networkLogger.bitrateChangeEndpointLogs, - "media.bitrateChange", - sessionId, - ); - - await sendMediaEvent(alloy, "media.statesUpdate", sessionId, { - statesStart: [ - { - name: "mute", - }, - { - name: "pictureInPicture", - }, - ], - statesEnd: [ - { - name: "fullScreen", - }, - ], - }); - await assertEventIsSent( - networkLogger.statesUpdateEndpointLogs, - "media.statesUpdate", - sessionId, - ); - - await sleep(11000); - await assertPingsSent(sessionId); - await assertPingsNotSentWhenSessionClosed(alloy); -}); diff --git a/packages/core/test/functional/specs/MediaCollection/MA2.js b/packages/core/test/functional/specs/MediaCollection/MA2.js deleted file mode 100644 index 8f10fb3e1..000000000 --- a/packages/core/test/functional/specs/MediaCollection/MA2.js +++ /dev/null @@ -1,384 +0,0 @@ -/* -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 { ClientFunction, t } from "testcafe"; -import createNetworkLogger from "../../helpers/networkLogger/index.js"; -import { responseStatus } from "../../helpers/assertions/index.js"; -import createFixture from "../../helpers/createFixture/index.js"; -import { compose } from "../../helpers/constants/configParts/index.js"; -import getResponseBody from "../../helpers/networkLogger/getResponseBody.js"; -import createResponse from "../../helpers/createResponse.js"; -import { TEST_PAGE as TEST_PAGE_URL } from "../../helpers/constants/url.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; -import orgMediaConfig from "../../helpers/constants/configParts/orgMediaConfig.js"; -import streamingMedia from "../../helpers/constants/configParts/streamingMedia.js"; -import { sleep } from "../Migration/helper.js"; - -const networkLogger = createNetworkLogger(); -const config = compose(orgMediaConfig, streamingMedia); -createFixture({ - title: "Streaming media for legacy migration use cases.", - url: TEST_PAGE_URL, - requestHooks: [ - networkLogger.edgeEndpointLogs, - networkLogger.mediaPauseEndpointLogs, - networkLogger.mediaPlayEndpointLogs, - networkLogger.chapterStartEndpointLogs, - networkLogger.pingEndpointLogs, - networkLogger.chapterCompleteEndpointLogs, - networkLogger.chapterSkipEndpointLogs, - networkLogger.adStartEndpointLogs, - networkLogger.adBreakStartEndpointLogs, - networkLogger.adBreakCompleteEndpointLogs, - networkLogger.adSkipEndpointLogs, - networkLogger.adCompleteEndpointLogs, - networkLogger.errorEndpointLogs, - networkLogger.sessionCompleteEndpointLogs, - networkLogger.sessionEndEndpointLogs, - networkLogger.statesUpdateEndpointLogs, - networkLogger.bitrateChangeEndpointLogs, - networkLogger.bufferStartEndpointLogs, - ], -}); - -test.meta({ - ID: "MA3", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -const assertSessionStarted = async () => { - await t.expect(networkLogger.edgeEndpointLogs.count(() => true)).gte(1); - await responseStatus(networkLogger.edgeEndpointLogs.requests, [200, 207]); - await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(1); - - const createSession = networkLogger.edgeEndpointLogs.requests[0]; - const requestBody = JSON.parse(createSession.request.body); - await t.expect(requestBody.events[0].xdm.eventType).eql("media.sessionStart"); - await t.expect(requestBody.events[0].xdm.mediaCollection.playhead).eql(0); - const response = JSON.parse( - getResponseBody(networkLogger.edgeEndpointLogs.requests[0]), - ); - const mediaCollectionPayload = createResponse({ - content: response, - }).getPayloadsByType("media-analytics:new-session"); - - return mediaCollectionPayload[0].sessionId; -}; - -const assertPingsNotSent = async () => { - await sleep(10000); - const secondPingEventRequest = networkLogger.pingEndpointLogs.requests[2]; - await t.expect(secondPingEventRequest).eql(undefined); -}; -const assertPingsSent = async (sessionId) => { - await t.expect(networkLogger.pingEndpointLogs.count(() => true)).gte(1); - const pingEventRequest = networkLogger.pingEndpointLogs.requests[0]; - const pingEvent = JSON.parse(pingEventRequest.request.body).events[0]; - await t.expect(pingEvent.xdm.mediaCollection.sessionID).eql(sessionId); - await t.expect(pingEvent.xdm.eventType).eql("media.ping"); -}; -const assertEventIsSent = async ( - endpointLogs, - eventType, - sessionId, - playhead, - order = 0, -) => { - await t.expect(endpointLogs.count(() => true)).gte(order + 1); - const eventRequest = endpointLogs.requests[order]; - await responseStatus(endpointLogs.requests, 204); - - const event = JSON.parse(eventRequest.request.body).events[0]; - await t.expect(event.xdm.mediaCollection.sessionID).eql(sessionId); - await t.expect(event.xdm.mediaCollection.playhead).eql(playhead); - await t.expect(event.xdm.eventType).eql(eventType); -}; - -const initializeTracker = ClientFunction(() => { - return window.alloy("getMediaAnalyticsTracker").then((Media) => { - window.Media = Media; - window.mediaTrackerInstance = Media.getInstance(); - return Media; - }); -}); - -const trackEvent = ClientFunction((eventType) => { - const event = window.Media.Event[eventType]; - window.mediaTrackerInstance.trackEvent(event); -}); -const trackPlay = ClientFunction(() => { - window.mediaTrackerInstance.trackPlay(); -}); -const trackPause = ClientFunction(() => { - window.mediaTrackerInstance.trackPause(); -}); -const updatePlayhead = ClientFunction((playhead) => { - window.mediaTrackerInstance.updatePlayhead(playhead); -}); - -const startChapter = ClientFunction(() => { - const chapterContextData = { - segmentType: "Sample segment type", - }; - const chapterInfo = window.Media.createChapterObject( - "chapterNumber1", - 2, - 18, - 1, - ); - window.mediaTrackerInstance.trackEvent( - window.Media.Event.ChapterStart, - chapterInfo, - chapterContextData, - ); -}); - -const trackSessionStart = ClientFunction(() => { - const Media = window.Media; - const tracker = window.mediaTrackerInstance; - const mediaInfo = Media.createMediaObject( - "NinasVideoName", - "Ninas player video", - 60, - Media.StreamType.VOD, - Media.MediaType.Video, - ); - const contextData = { - isUserLoggedIn: "false", - tvStation: "Sample TV station", - programmer: "Sample programmer", - assetID: "/uri-reference", - }; - - contextData[Media.VideoMetadataKeys.Episode] = "Sample Episode"; - contextData[Media.VideoMetadataKeys.Show] = "Sample Show"; - - tracker.trackSessionStart(mediaInfo, contextData); -}); - -const trackAds = ClientFunction(() => { - const tracker = window.mediaTrackerInstance; - - const adObject = window.Media.createAdObject("ad-name", "ad-id", 1, 15.0); - - const adMetadata = {}; - // Standard metadata keys provided by adobe. - adMetadata[window.Media.AdMetadataKeys.Advertiser] = "Sample Advertiser"; - adMetadata[window.Media.AdMetadataKeys.CampaignId] = "Sample Campaign"; - // Custom metadata keys - adMetadata.affiliate = "Sample affiliate"; - - tracker.trackEvent(window.Media.Event.AdStart, adObject, adMetadata); - - // AdComplete - tracker.trackEvent(window.Media.Event.AdComplete); - - // AdSkip - tracker.trackEvent(window.Media.Event.AdSkip); - - // AdBreakStart - const adBreakObject = window.Media.createAdBreakObject("preroll", 1, 0); - tracker.trackEvent(window.Media.Event.AdBreakStart, adBreakObject); - - // AdBreakComplete - tracker.trackEvent(window.Media.Event.AdBreakComplete); -}); - -const trackError = ClientFunction((errorId) => { - window.mediaTrackerInstance.trackError(errorId); -}); - -const trackPlaybackEvents = ClientFunction(() => { - // BufferStart - window.mediaTrackerInstance.trackEvent(window.Media.Event.BufferStart); - - // BufferComplete - window.mediaTrackerInstance.trackEvent(window.Media.Event.BufferComplete); - - // SeekStart - window.mediaTrackerInstance.trackEvent(window.Media.Event.SeekStart); - - // SeekComplete - window.mediaTrackerInstance.trackEvent(window.Media.Event.SeekComplete); -}); - -const bitrateChange = ClientFunction(() => { - const qoeObject = window.Media.createQoEObject(1000000, 24, 25, 10); - window.mediaTrackerInstance.updateQoEObject(qoeObject); - - // Bitrate change - window.mediaTrackerInstance.trackEvent(window.Media.Event.BitrateChange); -}); - -const stateChanges = ClientFunction(() => { - // StateStart (ex: Mute is switched on) - const stateObject = window.Media.createStateObject( - window.Media.PlayerState.Mute, - ); - window.mediaTrackerInstance.trackEvent( - window.Media.Event.StateStart, - stateObject, - ); - - // StateEnd - window.mediaTrackerInstance.trackEvent( - window.Media.Event.StateEnd, - stateObject, - ); -}); - -const sessionComplete = ClientFunction(() => { - window.mediaTrackerInstance.trackComplete(); -}); - -test("Test that legacy component send pings automatically and events are transformed correctly into XDM objects.", async () => { - const alloy = createAlloyProxy(); - await alloy.configure(config); - await initializeTracker(); - await trackSessionStart(); - const sessionId = await assertSessionStarted(); - - // play event - await trackPlay(); - await assertEventIsSent( - networkLogger.mediaPlayEndpointLogs, - "media.play", - sessionId, - 0, - ); - - // pause event - await trackPause(); - await assertEventIsSent( - networkLogger.mediaPauseEndpointLogs, - "media.pauseStart", - sessionId, - 0, - ); - - // chapter start event - await startChapter(); - await assertEventIsSent( - networkLogger.chapterStartEndpointLogs, - "media.chapterStart", - sessionId, - 0, - ); - - await updatePlayhead(10); - - await trackEvent("ChapterComplete"); - - // chapter skip event - await trackEvent("ChapterSkip"); - - await trackPlaybackEvents(); - // bitrate change event - await bitrateChange(); - await stateChanges(); - // error event - await trackError("test-buffer-start"); - // ad break start event - - await trackAds(); - await assertEventIsSent( - networkLogger.chapterCompleteEndpointLogs, - "media.chapterComplete", - sessionId, - 10, - ); - - await assertEventIsSent( - networkLogger.chapterSkipEndpointLogs, - "media.chapterSkip", - sessionId, - 10, - ); - - await assertEventIsSent( - networkLogger.adBreakStartEndpointLogs, - "media.adBreakStart", - sessionId, - 10, - ); - await assertEventIsSent( - networkLogger.adStartEndpointLogs, - "media.adStart", - sessionId, - 10, - ); - await assertEventIsSent( - networkLogger.adCompleteEndpointLogs, - "media.adComplete", - sessionId, - 10, - ); - await assertEventIsSent( - networkLogger.adBreakCompleteEndpointLogs, - "media.adBreakComplete", - sessionId, - 10, - ); - await assertEventIsSent( - networkLogger.adSkipEndpointLogs, - "media.adSkip", - sessionId, - 10, - ); - - await assertEventIsSent( - networkLogger.errorEndpointLogs, - "media.error", - sessionId, - 10, - ); - - await assertEventIsSent( - networkLogger.bufferStartEndpointLogs, - "media.bufferStart", - sessionId, - 10, - ); - await assertEventIsSent( - networkLogger.mediaPlayEndpointLogs, - "media.play", - sessionId, - 10, - 1, - ); - - await assertEventIsSent( - networkLogger.bitrateChangeEndpointLogs, - "media.bitrateChange", - sessionId, - 10, - ); - await assertEventIsSent( - networkLogger.statesUpdateEndpointLogs, - "media.statesUpdate", - sessionId, - 10, - 0, - ); - await assertEventIsSent( - networkLogger.statesUpdateEndpointLogs, - "media.statesUpdate", - sessionId, - 10, - 1, - ); - await sleep(10000); - await assertPingsSent(sessionId); - await sessionComplete(); - await sleep(10000); - await assertPingsNotSent(); -}); diff --git a/packages/core/test/functional/specs/MediaCollection/MA3.js b/packages/core/test/functional/specs/MediaCollection/MA3.js deleted file mode 100644 index 429a81b0e..000000000 --- a/packages/core/test/functional/specs/MediaCollection/MA3.js +++ /dev/null @@ -1,286 +0,0 @@ -/* -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 { t } from "testcafe"; -import createNetworkLogger from "../../helpers/networkLogger/index.js"; -import { responseStatus } from "../../helpers/assertions/index.js"; -import createFixture from "../../helpers/createFixture/index.js"; -import { compose } from "../../helpers/constants/configParts/index.js"; -import getResponseBody from "../../helpers/networkLogger/getResponseBody.js"; -import createResponse from "../../helpers/createResponse.js"; -import { TEST_PAGE as TEST_PAGE_URL } from "../../helpers/constants/url.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; -import orgMediaConfig from "../../helpers/constants/configParts/orgMediaConfig.js"; -import streamingMedia from "../../helpers/constants/configParts/streamingMedia.js"; -import { sleep } from "../Migration/helper.js"; - -const networkLogger = createNetworkLogger(); -const config = compose(orgMediaConfig, streamingMedia); -createFixture({ - title: "Streaming media in non-automatic mode", - url: TEST_PAGE_URL, - requestHooks: [ - networkLogger.edgeEndpointLogs, - networkLogger.mediaPauseEndpointLogs, - networkLogger.mediaPlayEndpointLogs, - networkLogger.chapterStartEndpointLogs, - networkLogger.pingEndpointLogs, - networkLogger.chapterCompleteEndpointLogs, - networkLogger.chapterSkipEndpointLogs, - networkLogger.adStartEndpointLogs, - networkLogger.adBreakStartEndpointLogs, - networkLogger.adBreakCompleteEndpointLogs, - networkLogger.adSkipEndpointLogs, - networkLogger.adCompleteEndpointLogs, - networkLogger.errorEndpointLogs, - networkLogger.sessionCompleteEndpointLogs, - networkLogger.sessionEndEndpointLogs, - networkLogger.statesUpdateEndpointLogs, - networkLogger.bitrateChangeEndpointLogs, - networkLogger.bufferStartEndpointLogs, - ], -}); - -test.meta({ - ID: "MA3", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); -const assertSessionStarted = async (alloy) => { - const sessionPromise = await alloy.createMediaSession({ - xdm: { - mediaCollection: { - playhead: 0, - sessionDetails: { - length: 60, - contentType: "VOD", - name: "test name of the video", - }, - }, - }, - }); - await responseStatus(networkLogger.edgeEndpointLogs.requests, [200, 207]); - await t.expect(networkLogger.edgeEndpointLogs.requests.length).eql(1); - - const createSession = networkLogger.edgeEndpointLogs.requests[0]; - const requestBody = JSON.parse(createSession.request.body); - await t.expect(requestBody.events[0].xdm.eventType).eql("media.sessionStart"); - await t.expect(requestBody.events[0].xdm.mediaCollection.playhead).eql(0); - const response = JSON.parse( - getResponseBody(networkLogger.edgeEndpointLogs.requests[0]), - ); - const mediaCollectionPayload = createResponse({ - content: response, - }).getPayloadsByType("media-analytics:new-session"); - await t - .expect(mediaCollectionPayload[0].sessionId) - .eql(sessionPromise.sessionId); - - return sessionPromise; -}; - -const assertPingsNotSent = async () => { - await sleep(10000); - - const secondPingEventRequest = networkLogger.pingEndpointLogs.requests[0]; - await t.expect(secondPingEventRequest).eql(undefined); -}; -const sendMediaEvent = async ( - alloy, - eventType, - sessionId, - additionalData = {}, -) => { - await alloy.sendMediaEvent({ - xdm: { - eventType, - mediaCollection: { - playhead: 1, - sessionID: sessionId, - ...additionalData, - }, - }, - }); -}; - -const assertEventIsSent = async (endpointLogs, eventType, sessionId) => { - const eventRequest = endpointLogs.requests[0]; - await responseStatus(endpointLogs.requests, 204); - - const event = JSON.parse(eventRequest.request.body).events[0]; - await t.expect(event.xdm.mediaCollection.sessionID).eql(sessionId); - await t.expect(event.xdm.eventType).eql(eventType); -}; - -test("Test that MC component doesn't send pings automatically", async () => { - const alloy = createAlloyProxy(); - await alloy.configure(config); - const { sessionId } = await assertSessionStarted(alloy); - // play event - await sendMediaEvent(alloy, "media.play", sessionId); - await assertEventIsSent( - networkLogger.mediaPlayEndpointLogs, - "media.play", - sessionId, - ); - - // pause event - await sendMediaEvent(alloy, "media.pauseStart", sessionId); - await assertEventIsSent( - networkLogger.mediaPauseEndpointLogs, - "media.pauseStart", - sessionId, - ); - - // chapter start event - await sendMediaEvent(alloy, "media.chapterStart", sessionId, { - chapterDetails: { - friendlyName: "Chapter 1", - length: 10, - index: 1, - offset: 0, - }, - }); - await assertEventIsSent( - networkLogger.chapterStartEndpointLogs, - "media.chapterStart", - sessionId, - ); - - // chapter complete event - await sendMediaEvent(alloy, "media.chapterComplete", sessionId); - await assertEventIsSent( - networkLogger.chapterCompleteEndpointLogs, - "media.chapterComplete", - sessionId, - ); - - // chapter skip event - await sendMediaEvent(alloy, "media.chapterSkip", sessionId); - await assertEventIsSent( - networkLogger.chapterSkipEndpointLogs, - "media.chapterSkip", - sessionId, - ); - - // ad break start event - await sendMediaEvent(alloy, "media.adBreakStart", sessionId, { - advertisingPodDetails: { - friendlyName: "Mid-roll", - offset: 0, - index: 1, - }, - }); - await assertEventIsSent( - networkLogger.adBreakStartEndpointLogs, - "media.adBreakStart", - sessionId, - ); - // ad start event - await sendMediaEvent(alloy, "media.adStart", sessionId, { - advertisingDetails: { - friendlyName: "Ad 1", - name: "/uri-reference/001", - length: 10, - advertiser: "Adobe Marketing", - campaignID: "Adobe Analytics", - creativeID: "creativeID", - creativeURL: "https://creativeurl.com", - placementID: "placementID", - siteID: "siteID", - podPosition: 11, - playerName: "HTML5 player", - }, - }); - await assertEventIsSent( - networkLogger.adStartEndpointLogs, - "media.adStart", - sessionId, - ); - - // ad complete event - await sendMediaEvent(alloy, "media.adComplete", sessionId); - await assertEventIsSent( - networkLogger.adCompleteEndpointLogs, - "media.adComplete", - sessionId, - ); - // ad break complete event - await sendMediaEvent(alloy, "media.adBreakComplete", sessionId); - await assertEventIsSent( - networkLogger.adBreakCompleteEndpointLogs, - "media.adBreakComplete", - sessionId, - ); - // ad skip event - await sendMediaEvent(alloy, "media.adSkip", sessionId); - await assertEventIsSent( - networkLogger.adSkipEndpointLogs, - "media.adSkip", - sessionId, - ); - // error event - await sendMediaEvent(alloy, "media.error", sessionId, { - errorDetails: { - name: "test-buffer-start", - source: "player", - }, - }); - await assertEventIsSent( - networkLogger.errorEndpointLogs, - "media.error", - sessionId, - ); - // bitrate change event - await sendMediaEvent(alloy, "media.bufferStart", sessionId); - await assertEventIsSent( - networkLogger.bufferStartEndpointLogs, - "media.bufferStart", - sessionId, - ); - // bitrate change event - await sendMediaEvent(alloy, "media.bitrateChange", sessionId, { - qoeDataDetails: { - framesPerSecond: 1, - bitrate: 35000, - droppedFrames: 30, - timeToStart: 1364, - }, - }); - await assertEventIsSent( - networkLogger.bitrateChangeEndpointLogs, - "media.bitrateChange", - sessionId, - ); - // states update event - await sendMediaEvent(alloy, "media.statesUpdate", sessionId, { - statesStart: [ - { - name: "mute", - }, - { - name: "pictureInPicture", - }, - ], - statesEnd: [ - { - name: "fullScreen", - }, - ], - }); - await assertEventIsSent( - networkLogger.statesUpdateEndpointLogs, - "media.statesUpdate", - sessionId, - ); - - await assertPingsNotSent(alloy); -}); diff --git a/packages/core/test/functional/specs/Migration/C8085773.js b/packages/core/test/functional/specs/Migration/C8085773.js deleted file mode 100644 index e9101f978..000000000 --- a/packages/core/test/functional/specs/Migration/C8085773.js +++ /dev/null @@ -1,104 +0,0 @@ -/* -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 } from "testcafe"; -import createNetworkLogger from "../../helpers/networkLogger/index.js"; -import createFixture from "../../helpers/createFixture/index.js"; -import { - compose, - orgMainConfigMain, - debugEnabled, - targetMigrationEnabled, -} from "../../helpers/constants/configParts/index.js"; -import { TEST_PAGE, TEST_PAGE_AT_JS_ONE } from "../../helpers/constants/url.js"; -import { - MBOX_EDGE_CLUSTER, - MBOX, -} from "../../../../src/constants/legacyCookies.js"; -import { - assertKonductorReturnsCookieAndCookieIsSet, - assertSameLocationHintIsUsed, - assertTargetMigrationEnabledIsSent, -} from "./helper.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; - -const networkLogger = createNetworkLogger(); -const config = compose(orgMainConfigMain, debugEnabled, targetMigrationEnabled); - -createFixture({ - title: - "C8085773: Web SDK to At.js 1.x - Assert same session ID, edge cluster are used for both of the requests " + - "interact and delivery API", - requestHooks: [ - networkLogger.edgeEndpointLogs, - networkLogger.targetMboxJsonEndpointLogs, - ], - url: TEST_PAGE, - includeAlloyLibrary: true, -}); - -test.meta({ - ID: "C8085773", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -test( - "C8085773: Web SDK to At.js 1.x - Assert same session ID, edge cluster are used for both of the requests " + - "interact and delivery API", - async () => { - // Loaded a page with Alloy - const alloy = createAlloyProxy(); - await alloy.configure(config); - await alloy.sendEvent(); - - const sendEventRequest = networkLogger.edgeEndpointLogs.requests[0]; - - // Check that targetMigrationEnabled flag is sent in meta - await assertTargetMigrationEnabledIsSent(sendEventRequest); - - // Check that mbox cookie is present in the response from Konductor - const mboxCookie = await assertKonductorReturnsCookieAndCookieIsSet( - MBOX, - sendEventRequest, - ); - - // Check that mboxEdgeCluster cookie is present in the response from Konductor - const mboxEdgeClusterCookie = - await assertKonductorReturnsCookieAndCookieIsSet( - MBOX_EDGE_CLUSTER, - sendEventRequest, - ); - - // NAVIGATE to clean page - await t.navigateTo(TEST_PAGE_AT_JS_ONE); - // get mbox json API request - await t - .expect(networkLogger.targetMboxJsonEndpointLogs.count(() => true)) - .eql(1); - const mboxJsonRequest = - networkLogger.targetMboxJsonEndpointLogs.requests[0]; - const requestUrl = mboxJsonRequest.request.url; - const { searchParams, hostname } = new URL(requestUrl); - - // assert session IDs are the same for both requests - const sessionIdFromMboxJsonRequest = searchParams.get("mboxSession"); - await t - .expect(mboxCookie) - .contains( - `#${sessionIdFromMboxJsonRequest}#`, - "Session ID returned from Target Upstream does not match the session ID sent in the request to Target", - ); - - // assert the same cluster is used - await assertSameLocationHintIsUsed(hostname, mboxEdgeClusterCookie); - }, -); diff --git a/packages/core/test/functional/specs/Migration/C8085774.js b/packages/core/test/functional/specs/Migration/C8085774.js deleted file mode 100644 index 1f16ad904..000000000 --- a/packages/core/test/functional/specs/Migration/C8085774.js +++ /dev/null @@ -1,103 +0,0 @@ -/* -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 } from "testcafe"; -import createNetworkLogger from "../../helpers/networkLogger/index.js"; -import createFixture from "../../helpers/createFixture/index.js"; -import { - compose, - orgMainConfigMain, - debugEnabled, - targetMigrationEnabled, -} from "../../helpers/constants/configParts/index.js"; -import { TEST_PAGE, TEST_PAGE_AT_JS_TWO } from "../../helpers/constants/url.js"; -import { - MBOX_EDGE_CLUSTER, - MBOX, -} from "../../../../src/constants/legacyCookies.js"; -import { - assertKonductorReturnsCookieAndCookieIsSet, - assertSameLocationHintIsUsed, - assertTargetMigrationEnabledIsSent, -} from "./helper.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; - -const networkLogger = createNetworkLogger(); -const config = compose(orgMainConfigMain, debugEnabled, targetMigrationEnabled); - -createFixture({ - title: - "C8085774: Web SDK to At.js 2.x - Assert same session ID, edge cluster are used for " + - "both of the requests interact and delivery API", - requestHooks: [ - networkLogger.edgeEndpointLogs, - networkLogger.targetDeliveryEndpointLogs, - ], - url: TEST_PAGE, - includeAlloyLibrary: true, -}); - -test.meta({ - ID: "C8085774", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -test( - "C8085774: Web SDK to At.js 2.x - Assert same session ID, edge cluster are used for both of the " + - "requests interact and delivery API", - async () => { - // Loaded a page with Alloy - const alloy = createAlloyProxy(); - await alloy.configure(config); - await alloy.sendEvent(); - - const sendEventRequest = networkLogger.edgeEndpointLogs.requests[0]; - - // Check that targetMigrationEnabled flag is sent in meta - await assertTargetMigrationEnabledIsSent(sendEventRequest); - // Check that mbox cookie is present in the response from Konductor - const mboxCookie = await assertKonductorReturnsCookieAndCookieIsSet( - MBOX, - sendEventRequest, - ); - - // Check that mboxEdgeCluster cookie is present in the response from Konductor - const mboxEdgeClusterCookie = - await assertKonductorReturnsCookieAndCookieIsSet( - MBOX_EDGE_CLUSTER, - sendEventRequest, - ); - - // NAVIGATE to clean page - await t.navigateTo(TEST_PAGE_AT_JS_TWO); - // get delivery API request adding sleep to make sure the request was triggered - await t - .expect(networkLogger.targetDeliveryEndpointLogs.count(() => true)) - .eql(1); - const deliveryRequest = - networkLogger.targetDeliveryEndpointLogs.requests[0]; - const requestUrl = deliveryRequest.request.url; - const { searchParams, hostname } = new URL(requestUrl); - - // assert session IDs are the same for both requests - const sessionIdFromDeliveryRequest = searchParams.get("sessionId"); - await t - .expect(mboxCookie) - .contains( - `#${sessionIdFromDeliveryRequest}#`, - "Session ID returned from Target Upstream does not match the session ID sent to delivery API", - ); - - // assert the same cluster is used - await assertSameLocationHintIsUsed(hostname, mboxEdgeClusterCookie); - }, -); diff --git a/packages/core/test/functional/specs/Migration/C8085775.js b/packages/core/test/functional/specs/Migration/C8085775.js deleted file mode 100644 index d3951c134..000000000 --- a/packages/core/test/functional/specs/Migration/C8085775.js +++ /dev/null @@ -1,102 +0,0 @@ -/* -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 } from "testcafe"; -import createNetworkLogger from "../../helpers/networkLogger/index.js"; -import createFixture from "../../helpers/createFixture/index.js"; -import { - compose, - orgMainConfigMain, - debugEnabled, - targetMigrationEnabled, -} from "../../helpers/constants/configParts/index.js"; -import { TEST_PAGE, TEST_PAGE_AT_JS_ONE } from "../../helpers/constants/url.js"; -import cookies from "../../helpers/cookies.js"; -import { - MBOX_EDGE_CLUSTER, - MBOX, -} from "../../../../src/constants/legacyCookies.js"; -import { - assertTargetMigrationEnabledIsSent, - getLocationHint, - injectAlloyAndSendEvent, -} from "./helper.js"; -import { responseStatus } from "../../helpers/assertions/index.js"; - -const networkLogger = createNetworkLogger(); -const config = compose(orgMainConfigMain, debugEnabled, targetMigrationEnabled); - -createFixture({ - title: - "C8085775: At.js 1.x to Web SDK - Assert same session ID, edge cluster are " + - "used for both of the requests interact and delivery API", - requestHooks: [ - networkLogger.edgeEndpointLogs, - networkLogger.targetMboxJsonEndpointLogs, - ], - url: TEST_PAGE_AT_JS_ONE, - includeAlloyLibrary: false, -}); - -test.meta({ - ID: "C8085775", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -test( - "C8085775: At.js 1.x to Web SDK - Assert same session ID, edge cluster are " + - "used for both of the requests interact and delivery API", - async () => { - await t - .expect(networkLogger.targetMboxJsonEndpointLogs.count(() => true)) - .eql(1); - // Get mbox/json API request - const mboxJsonRequest = - networkLogger.targetMboxJsonEndpointLogs.requests[0]; - await responseStatus(networkLogger.targetMboxJsonEndpointLogs, [200, 207]); - const { searchParams } = new URL(mboxJsonRequest.request.url); - // Extract the session ID from the request query params - const sessionIdFromMboxJsonRequest = searchParams.get("mboxSession"); - const mboxEdgeClusterCookieValue = await cookies.get(MBOX_EDGE_CLUSTER); - await t.expect(mboxEdgeClusterCookieValue).ok(); - // Check that mbox cookie is set - const mboxCookieValue = await cookies.get(MBOX); - await t.expect(mboxCookieValue).ok(); - - // NAVIGATE to a web sdk page - await t.navigateTo(TEST_PAGE); - await injectAlloyAndSendEvent(config); - const sendEventRequest = networkLogger.edgeEndpointLogs.requests[0]; - const requestBody = JSON.parse(sendEventRequest.request.body); - - // Check that targetMigrationEnabled is sent in meta - await assertTargetMigrationEnabledIsSent(sendEventRequest); - // Extract location hint - const { pathname } = new URL(sendEventRequest.request.url); - const aepRequestLocationHint = getLocationHint(pathname); - // Assert the location hint used for interact endpoint is the same as in mboxEdgeCluster Cookie value - await t.expect(mboxEdgeClusterCookieValue).eql(aepRequestLocationHint); - // Check that mbox cookie is present in the request state - const { entries: stateStore } = requestBody.meta.state; - - const requestMboxCookie = stateStore.find((entry) => { - return entry.key.includes(MBOX); - }); - // Assert the session IDs are the same - await t - .expect(requestMboxCookie.value) - .contains( - `#${sessionIdFromMboxJsonRequest}#`, - "Session ID from request should be eql to session ID from mbox cookie sent in meta.state", - ); - }, -); diff --git a/packages/core/test/functional/specs/Migration/C8085776.js b/packages/core/test/functional/specs/Migration/C8085776.js deleted file mode 100644 index 723a8265d..000000000 --- a/packages/core/test/functional/specs/Migration/C8085776.js +++ /dev/null @@ -1,102 +0,0 @@ -/* -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 } from "testcafe"; -import createNetworkLogger from "../../helpers/networkLogger/index.js"; -import createFixture from "../../helpers/createFixture/index.js"; -import { - compose, - orgMainConfigMain, - debugEnabled, - targetMigrationEnabled, -} from "../../helpers/constants/configParts/index.js"; -import { TEST_PAGE, TEST_PAGE_AT_JS_TWO } from "../../helpers/constants/url.js"; -import cookies from "../../helpers/cookies.js"; -import { - MBOX_EDGE_CLUSTER, - MBOX, -} from "../../../../src/constants/legacyCookies.js"; -import { - assertTargetMigrationEnabledIsSent, - getLocationHint, - injectAlloyAndSendEvent, -} from "./helper.js"; -import { responseStatus } from "../../helpers/assertions/index.js"; - -const networkLogger = createNetworkLogger(); -const config = compose(orgMainConfigMain, debugEnabled, targetMigrationEnabled); - -createFixture({ - title: - "C8085776: At.js 2.x to Web SDK - Assert same session ID, edge cluster are used " + - "for both of the requests interact and delivery API", - requestHooks: [ - networkLogger.edgeEndpointLogs, - networkLogger.targetDeliveryEndpointLogs, - ], - url: TEST_PAGE_AT_JS_TWO, - includeAlloyLibrary: false, -}); - -test.meta({ - ID: "C8085776", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -test( - "C8085776: At.js 2.x to Web SDK - Assert same session ID, edge cluster are used " + - "for both of the requests interact and delivery API", - async () => { - await t - .expect(networkLogger.targetDeliveryEndpointLogs.count(() => true)) - .eql(1); - // Get delivery API request - const deliveryRequest = - networkLogger.targetDeliveryEndpointLogs.requests[0]; - await responseStatus(networkLogger.targetDeliveryEndpointLogs, [200, 207]); - const { searchParams } = new URL(deliveryRequest.request.url); - // Extract the session ID from the request query params - const sessionIdFromDeliveryRequest = searchParams.get("sessionId"); - const mboxEdgeClusterCookieValue = await cookies.get(MBOX_EDGE_CLUSTER); - await t.expect(mboxEdgeClusterCookieValue).ok(); - // Check that mbox cookie is set - const mboxCookieValue = await cookies.get(MBOX); - await t.expect(mboxCookieValue).ok(); - - // NAVIGATE to a web sdk page - await t.navigateTo(TEST_PAGE); - await injectAlloyAndSendEvent(config); - const sendEventRequest = networkLogger.edgeEndpointLogs.requests[0]; - const requestBody = JSON.parse(sendEventRequest.request.body); - - // Check that targetMigrationEnabled is sent in meta - await assertTargetMigrationEnabledIsSent(sendEventRequest); - // Extract location hint - const { pathname } = new URL(sendEventRequest.request.url); - const aepRequestLocationHint = getLocationHint(pathname); - // Assert the location hint used for interact endpoint is the same as in mboxEdgeCluster Cookie value - await t.expect(mboxEdgeClusterCookieValue).eql(aepRequestLocationHint); - // Check that mbox cookie is present in the request state - const { entries: stateStore } = requestBody.meta.state; - - const requestMboxCookie = stateStore.find((entry) => { - return entry.key.includes(MBOX); - }); - // Assert the session IDs are the same - await t - .expect(requestMboxCookie.value) - .contains( - `#${sessionIdFromDeliveryRequest}#`, - "Session ID from Delivery request should be eql to session ID from mbox cookie sent in meta.state", - ); - }, -); diff --git a/packages/core/test/functional/specs/Migration/C8085777.js b/packages/core/test/functional/specs/Migration/C8085777.js deleted file mode 100644 index 509e28ad5..000000000 --- a/packages/core/test/functional/specs/Migration/C8085777.js +++ /dev/null @@ -1,133 +0,0 @@ -/* -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 } from "testcafe"; -import createNetworkLogger from "../../helpers/networkLogger/index.js"; -import createFixture from "../../helpers/createFixture/index.js"; -import { - compose, - orgMainConfigMain, - debugEnabled, - targetMigrationEnabled, -} from "../../helpers/constants/configParts/index.js"; -import { TEST_PAGE, TEST_PAGE_AT_JS_TWO } from "../../helpers/constants/url.js"; -import getResponseBody from "../../helpers/networkLogger/getResponseBody.js"; -import { - MBOX_EDGE_CLUSTER, - MBOX, -} from "../../../../src/constants/legacyCookies.js"; -import { - assertKonductorReturnsCookieAndCookieIsSet, - assertSameLocationHintIsUsed, - assertTargetMigrationEnabledIsSent, - fetchMboxOffer, - MIGRATION_LOCATION, -} from "./helper.js"; -import migrationEnabled from "../../helpers/constants/configParts/migrationEnabled.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; - -const favoriteColor = "violet-1234"; -const networkLogger = createNetworkLogger(); -const config = compose( - orgMainConfigMain, - debugEnabled, - migrationEnabled, - targetMigrationEnabled, -); -createFixture({ - title: - "C8085777: Use same visitor profile in mixed mode implementation: Update profile attribute using " + - "web sdk and fetch offer based on profile attr using at.js 2.x", - requestHooks: [ - networkLogger.edgeEndpointLogs, - networkLogger.targetDeliveryEndpointLogs, - ], - url: TEST_PAGE, - includeAlloyLibrary: true, -}); - -test.meta({ - ID: "C8085777", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -test.skip( - "C8085777: Use same visitor profile in mixed mode implementation: Update profile attribute using " + - "web sdk and fetch offer based on profile attr using at.js 2.x", - async () => { - const options = { - renderDecisions: true, - data: { - __adobe: { - target: { - "profile.favoriteColor": favoriteColor, - }, - }, - }, - }; - // Loaded a page with Alloy - const alloy = createAlloyProxy(); - await alloy.configure(config); - await alloy.sendEvent(options); - await t.expect(networkLogger.edgeEndpointLogs.count(() => true)).eql(1); - const sendEventRequest = networkLogger.edgeEndpointLogs.requests[0]; - - // Check that targetMigrationEnabled flag is sent in meta - await assertTargetMigrationEnabledIsSent(sendEventRequest); - - // Check that mbox cookie is present in the response from Konductor - const mboxCookie = await assertKonductorReturnsCookieAndCookieIsSet( - MBOX, - sendEventRequest, - ); - - // Check that mboxEdgeCluster cookie is present in the response from Konductor - const mboxEdgeClusterCookie = - await assertKonductorReturnsCookieAndCookieIsSet( - MBOX_EDGE_CLUSTER, - sendEventRequest, - ); - - // NAVIGATE to clean page - await t.navigateTo(TEST_PAGE_AT_JS_TWO); - // get delivery API request adding sleep to make sure the request was triggered - await fetchMboxOffer({ mbox: MIGRATION_LOCATION }); - const deliveryRequest = - networkLogger.targetDeliveryEndpointLogs.requests[1]; - await t - .expect(networkLogger.targetDeliveryEndpointLogs.count(() => true)) - .eql(2); - // Extract state:store payload - const deliveryResponse = JSON.parse(getResponseBody(deliveryRequest)); - - const mbox = deliveryResponse.execute.mboxes[0]; - - const content = mbox.options[0].content; - await t - .expect(content) - .eql(`The favorite Color for this visitor is ${favoriteColor}.`); - const requestUrl = deliveryRequest.request.url; - const { searchParams, hostname } = new URL(requestUrl); - - // assert session IDs are the same for both requests - const sessionIdFromDeliveryRequest = searchParams.get("sessionId"); - await t - .expect(mboxCookie) - .contains( - `#${sessionIdFromDeliveryRequest}#`, - "Session ID returned from Target Upstream does not match the session ID sent to delivery API", - ); - - // assert the same cluster is used - await assertSameLocationHintIsUsed(hostname, mboxEdgeClusterCookie); - }, -); diff --git a/packages/core/test/functional/specs/Migration/C8085778.js b/packages/core/test/functional/specs/Migration/C8085778.js deleted file mode 100644 index bdebae878..000000000 --- a/packages/core/test/functional/specs/Migration/C8085778.js +++ /dev/null @@ -1,120 +0,0 @@ -/* -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 } from "testcafe"; -import createNetworkLogger from "../../helpers/networkLogger/index.js"; -import createFixture from "../../helpers/createFixture/index.js"; -import { - compose, - orgMainConfigMain, - debugEnabled, - targetMigrationEnabled, -} from "../../helpers/constants/configParts/index.js"; -import { TEST_PAGE, TEST_PAGE_AT_JS_ONE } from "../../helpers/constants/url.js"; -import getResponseBody from "../../helpers/networkLogger/getResponseBody.js"; -import { - assertTargetMigrationEnabledIsSent, - fetchMboxOffer, - getEcid, - MIGRATION_LOCATION, - sleep, -} from "./helper.js"; -import migrationEnabled from "../../helpers/constants/configParts/migrationEnabled.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; -import createResponse from "../../helpers/createResponse.js"; - -const favoriteColor = "purple-123"; -const networkLogger = createNetworkLogger(); - -const config = compose( - orgMainConfigMain, - debugEnabled, - migrationEnabled, - targetMigrationEnabled, -); - -createFixture({ - title: - "C8085778: Use same visitor profile in mixed mode implementation - Update profile attribute " + - "using web sdk and fetch offer based on profile attr using at.js 1.x", - requestHooks: [ - networkLogger.edgeEndpointLogs, - networkLogger.targetMboxJsonEndpointLogs, - ], - url: TEST_PAGE, - includeAlloyLibrary: true, -}); - -test.meta({ - ID: "C8085778", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -test.skip( - "C8085778: Use same visitor profile in mixed mode implementation - Update profile attribute " + - "using web sdk and fetch offer based on profile attr using at.js 1.x", - async () => { - const options = { - renderDecisions: true, - data: { - __adobe: { - target: { - "profile.favoriteColor": favoriteColor, - }, - }, - }, - }; - const alloy = createAlloyProxy(); - await alloy.configure(config); - await alloy.sendEvent(options); - await sleep(3000); - const sendEventRequest = networkLogger.edgeEndpointLogs.requests[0]; - // Check that targetMigrationEnabled flag is sent in meta - await assertTargetMigrationEnabledIsSent(sendEventRequest); - - // Extract state:store payload - const response = JSON.parse( - getResponseBody(networkLogger.edgeEndpointLogs.requests[0]), - ); - - const identityPayload = createResponse({ - content: response, - }).getPayloadsByType("identity:result"); - const ecid = getEcid(identityPayload)[0].id; - - // NAVIGATE to clean page - await t.navigateTo(TEST_PAGE_AT_JS_ONE); - // get mbox json API request - await t - .expect(networkLogger.targetMboxJsonEndpointLogs.count(() => true)) - .eql(1); - await fetchMboxOffer({ - mbox: MIGRATION_LOCATION, - }); - await t - .expect(networkLogger.targetMboxJsonEndpointLogs.count(() => true)) - .eql(2); - const customMboxJsonRequest = - networkLogger.targetMboxJsonEndpointLogs.requests[1]; - const mboxRequestUrlQuery = new URL(customMboxJsonRequest.request.url) - .searchParams; - const ecidMboxJsonRequest = mboxRequestUrlQuery.get("mboxMCGVID"); - // assert both interact and mbox json requests are sending the same identity - await t.expect(ecid).eql(ecidMboxJsonRequest); - const mboxJsonResponse = JSON.parse(getResponseBody(customMboxJsonRequest)); - const mboxContent = mboxJsonResponse.offers[0].html; - - await t - .expect(mboxContent) - .eql(`The favorite Color for this visitor is ${favoriteColor}.`); - }, -); diff --git a/packages/core/test/functional/specs/Migration/C8085779.js b/packages/core/test/functional/specs/Migration/C8085779.js deleted file mode 100644 index 8c4ed4eeb..000000000 --- a/packages/core/test/functional/specs/Migration/C8085779.js +++ /dev/null @@ -1,108 +0,0 @@ -/* -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 } from "testcafe"; -import createNetworkLogger from "../../helpers/networkLogger/index.js"; -import createFixture from "../../helpers/createFixture/index.js"; -import { - compose, - orgMainConfigMain, - debugEnabled, - targetMigrationEnabled, -} from "../../helpers/constants/configParts/index.js"; -import { TEST_PAGE, TEST_PAGE_AT_JS_ONE } from "../../helpers/constants/url.js"; -import { - fetchMboxOffer, - getEcid, - getPropositionCustomContent, - injectAlloyAndSendEvent, - MIGRATION_LOCATION, -} from "./helper.js"; -import getResponseBody from "../../helpers/networkLogger/getResponseBody.js"; -import createResponse from "../../helpers/createResponse.js"; -import migrationEnabled from "../../helpers/constants/configParts/migrationEnabled.js"; -import { responseStatus } from "../../helpers/assertions/index.js"; - -const favoriteColor = "green-1234"; -const networkLogger = createNetworkLogger(); - -const config = compose( - orgMainConfigMain, - debugEnabled, - migrationEnabled, - targetMigrationEnabled, -); - -createFixture({ - title: - "C8085779: Use same visitor profile in mixed mode implementation: Update profile attribute using " + - "at.js 1.x and fetch proposition offer based on profile attr using web sdk", - requestHooks: [ - networkLogger.edgeEndpointLogs, - networkLogger.targetMboxJsonEndpointLogs, - ], - url: TEST_PAGE_AT_JS_ONE, - includeAlloyLibrary: false, -}); - -test.meta({ - ID: "C8085779", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -test( - "C8085779: Use same visitor profile in mixed mode implementation: Update profile attribute using " + - "at.js 1.x and fetch proposition offer based on profile attr using web sdk", - async () => { - // delivery API request - await fetchMboxOffer({ - params: { - "profile.favoriteColor": favoriteColor, - }, - }); - await t - .expect(networkLogger.targetMboxJsonEndpointLogs.count(() => true)) - .eql(2); - const mboxJsonRequest = - networkLogger.targetMboxJsonEndpointLogs.requests[1]; - await responseStatus(networkLogger.targetMboxJsonEndpointLogs, [200, 207]); - const mboxRequestUrlQuery = new URL(mboxJsonRequest.request.url) - .searchParams; - const marketingCloudVisitorId = mboxRequestUrlQuery.get("mboxMCGVID"); - - // NAVIGATE to a web sdk page - await t.navigateTo(TEST_PAGE); - await injectAlloyAndSendEvent(config, { - decisionScopes: [MIGRATION_LOCATION], - }); - const sendEventRequest = networkLogger.edgeEndpointLogs.requests[0]; - const response = JSON.parse(getResponseBody(sendEventRequest)); - const identityPayload = createResponse({ - content: response, - }).getPayloadsByType("identity:result"); - const ecid = getEcid(identityPayload)[0].id; - - // expect same ecid is used in both requests - await t.expect(marketingCloudVisitorId).eql(ecid); - const personalizationPayload = createResponse({ - content: response, - }).getPayloadsByType("personalization:decisions"); - - const propositionCustomContent = getPropositionCustomContent( - personalizationPayload, - ); - // expect to get a offer based on the profile attr updated in the previous call using legacy libs - await t - .expect(propositionCustomContent) - .eql(`The favorite Color for this visitor is ${favoriteColor}.`); - }, -); diff --git a/packages/core/test/functional/specs/Migration/C8085780.js b/packages/core/test/functional/specs/Migration/C8085780.js deleted file mode 100644 index 83ce80204..000000000 --- a/packages/core/test/functional/specs/Migration/C8085780.js +++ /dev/null @@ -1,104 +0,0 @@ -/* -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 } from "testcafe"; -import createNetworkLogger from "../../helpers/networkLogger/index.js"; -import createFixture from "../../helpers/createFixture/index.js"; -import { - compose, - orgMainConfigMain, - debugEnabled, - targetMigrationEnabled, -} from "../../helpers/constants/configParts/index.js"; -import { TEST_PAGE, TEST_PAGE_AT_JS_TWO } from "../../helpers/constants/url.js"; -import { - fetchMboxOffer, - getPropositionCustomContent, - injectAlloyAndSendEvent, - MIGRATION_LOCATION, -} from "./helper.js"; -import getResponseBody from "../../helpers/networkLogger/getResponseBody.js"; -import createResponse from "../../helpers/createResponse.js"; -import migrationEnabled from "../../helpers/constants/configParts/migrationEnabled.js"; -import { responseStatus } from "../../helpers/assertions/index.js"; - -const favoriteColor = "red-1234"; - -const networkLogger = createNetworkLogger(); -const config = compose( - orgMainConfigMain, - debugEnabled, - migrationEnabled, - targetMigrationEnabled, -); - -createFixture({ - title: - "C8085780: Use same visitor profile in mixed mode implementation - Update profile attribute " + - "using at.js 2.x and fetch proposition offer based on profile attr using web sdk", - requestHooks: [ - networkLogger.edgeEndpointLogs, - networkLogger.targetDeliveryEndpointLogs, - ], - url: TEST_PAGE_AT_JS_TWO, - includeAlloyLibrary: false, -}); - -test.meta({ - ID: "C8085780", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -test( - "C8085780: Use same visitor profile in mixed mode implementation - Update profile attribute " + - "using at.js 2.x and fetch proposition offer based on profile attr using web sdk", - async () => { - // delivery API request - await fetchMboxOffer({ - params: { - "profile.favoriteColor": favoriteColor, - }, - }); - await t - .expect(networkLogger.targetDeliveryEndpointLogs.count(() => true)) - .eql(2); - const deliveryRequest = - networkLogger.targetDeliveryEndpointLogs.requests[1]; - await responseStatus(networkLogger.targetDeliveryEndpointLogs, [200, 207]); - const requestBody = JSON.parse(deliveryRequest.request.body); - const { marketingCloudVisitorId } = requestBody.id; - - // NAVIGATE to a web sdk page - await t.navigateTo(TEST_PAGE); - await injectAlloyAndSendEvent(config, { - decisionScopes: [MIGRATION_LOCATION], - }); - const sendEventRequest = networkLogger.edgeEndpointLogs.requests[0]; - const response = JSON.parse(getResponseBody(sendEventRequest)); - const identityRequestBody = JSON.parse(sendEventRequest.request.body); - const ecid = identityRequestBody.xdm.identityMap.ECID[0].id; - - // expect same ecid is used in both requests - await t.expect(marketingCloudVisitorId).eql(ecid); - const personalizationPayload = createResponse({ - content: response, - }).getPayloadsByType("personalization:decisions"); - - const propositionCustomContent = getPropositionCustomContent( - personalizationPayload, - ); - // expect to get a offer based on the profile attr updated in the previous call using legacy libs - await t - .expect(propositionCustomContent) - .eql(`The favorite Color for this visitor is ${favoriteColor}.`); - }, -); diff --git a/packages/core/test/functional/specs/Migration/helper.js b/packages/core/test/functional/specs/Migration/helper.js deleted file mode 100644 index 1e0e9d16b..000000000 --- a/packages/core/test/functional/specs/Migration/helper.js +++ /dev/null @@ -1,113 +0,0 @@ -/* -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 { ClientFunction, t } from "testcafe"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; -import createConsoleLogger from "../../helpers/consoleLogger/index.js"; -import { injectAlloyDuringTest } from "../../helpers/createFixture/clientScripts.js"; -import cookies from "../../helpers/cookies.js"; -import getResponseBody from "../../helpers/networkLogger/getResponseBody.js"; -import createResponse from "../../helpers/createResponse.js"; - -export const MIGRATION_LOCATION = "location-for-migration-testing"; -export const sleep = (ms) => - new Promise((resolve) => { - setTimeout(resolve, ms); - }); - -export const extractCluster = (hostname) => { - const values = hostname.split("."); - return values[0]; -}; - -export const injectAlloyAndSendEvent = async (config, options = {}) => { - const alloy = createAlloyProxy(); - await alloy.configureAsync(config); - await alloy.getLibraryInfoAsync(); - const logger = await createConsoleLogger(); - await injectAlloyDuringTest(); - await logger.info.expectMessageMatching(/Executing getLibraryInfo command/); - await alloy.sendEvent(options); -}; - -export const assertTargetMigrationEnabledIsSent = async (sendEventRequest) => { - const requestBody = JSON.parse(sendEventRequest.request.body); - - await t.expect(requestBody.meta.target).eql({ migration: true }); -}; - -export const assertKonductorReturnsCookieAndCookieIsSet = async ( - cookieKey, - sendEventRequest, -) => { - // Extract state:store payload - const response = JSON.parse(getResponseBody(sendEventRequest)); - const stateStorePayload = createResponse({ - content: response, - }).getPayloadsByType("state:store"); - await t.expect(stateStorePayload.length).gte(0); - - const responseContainsCookie = stateStorePayload.find((entry) => { - return entry.key.includes(cookieKey); - }); - await t.expect(responseContainsCookie).ok(); - // Check that cookie is set - const cookieValue = await cookies.get(cookieKey); - await t.expect(cookieValue).ok(); - - return cookieValue; -}; - -export const getLocationHint = (pathname) => { - const values = pathname.split("/"); - const locationHint = values[2]; - - return Number(locationHint.split("t")[1]); -}; - -export const getEcid = (identityPayload) => { - return identityPayload.filter((obj) => obj.namespace.code === "ECID"); -}; - -export const getPropositionCustomContent = (personalizationPayload) => { - const decisionScopeProposition = personalizationPayload.filter( - (proposition) => proposition.scope === MIGRATION_LOCATION, - ); - - return decisionScopeProposition[0].items[0].data.content; -}; - -export const fetchMboxOffer = ClientFunction( - ({ params = {}, mbox = "target-global-mbox" }) => { - return window.adobe.target.getOffer({ - mbox, - params, - success(response) { - return response; - }, - // eslint-disable-next-line no-console - error: console.error, - }); - }, -); - -export const assertSameLocationHintIsUsed = async ( - hostname, - mboxEdgeClusterCookie, -) => { - const cluster = await extractCluster(hostname); - await t - .expect(`mboxedge${mboxEdgeClusterCookie}`) - .eql( - cluster, - "Cluster ID returned from Target Upstream does not match the cluster ID used in the path to Target Edge API", - ); -}; diff --git a/packages/core/test/functional/specs/Personalization/C11389844.js b/packages/core/test/functional/specs/Personalization/C11389844.js deleted file mode 100644 index 8bd707344..000000000 --- a/packages/core/test/functional/specs/Personalization/C11389844.js +++ /dev/null @@ -1,191 +0,0 @@ -/* -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 createNetworkLogger from "../../helpers/networkLogger/index.js"; -import { responseStatus } from "../../helpers/assertions/index.js"; -import createFixture from "../../helpers/createFixture/index.js"; -import addHtmlToBody from "../../helpers/dom/addHtmlToBody.js"; -import { - compose, - orgMainConfigMain, - debugEnabled, - thirdPartyCookiesDisabled, - ajoConfigForStage, -} from "../../helpers/constants/configParts/index.js"; -import getResponseBody from "../../helpers/networkLogger/getResponseBody.js"; -import createResponse from "../../helpers/createResponse.js"; -import { TEST_PAGE_WITH_CSP } from "../../helpers/constants/url.js"; -import flushPromiseChains from "../../helpers/flushPromiseChains.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; - -const networkLogger = createNetworkLogger(); -const config = compose( - orgMainConfigMain, - ajoConfigForStage, - debugEnabled, - thirdPartyCookiesDisabled, -); -const AJO_TEST_SURFACE = "web://alloyio.com/personalizationAjoSpa"; - -createFixture({ - title: "C11389844: AJO SPA support", - url: `${TEST_PAGE_WITH_CSP}?test=C11389844`, - requestHooks: [networkLogger.edgeEndpointLogs], -}); - -test.meta({ - ID: "C11389844", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -const getDecisionContent = ClientFunction((elementId) => { - const container = document.getElementById(elementId); - - return container.innerText; -}); - -const getDecisionsMetaByScope = (decisions, scope) => { - const metas = []; - - decisions.forEach((decision) => { - if (decision.scope === scope) { - metas.push({ - id: decision.id, - scope: decision.scope, - scopeDetails: decision.scopeDetails, - }); - } - }); - return metas; -}; - -const addContentContainer = () => { - return addHtmlToBody( - `
    - This is the AJO personalization placeholder for the products view. - Personalized content has not been loaded. -
    `, - ); -}; - -const simulatePageLoad = async (alloy) => { - const personalization = { surfaces: [AJO_TEST_SURFACE] }; - - await alloy.sendEvent({ - renderDecisions: true, - personalization, - }); - - // asserts the request fired to Experience Edge has the expected event query - await responseStatus(networkLogger.edgeEndpointLogs.requests, [200, 207]); - - const sendEventRequest = networkLogger.edgeEndpointLogs.requests[0]; - const requestBody = JSON.parse(sendEventRequest.request.body); - const surfaces = requestBody.events[0].query.personalization.surfaces; - const hasSurfaces = surfaces.includes(AJO_TEST_SURFACE); - - await t.expect(hasSurfaces).eql(true); - - const personalizationSchemas = - requestBody.events[0].query.personalization.schemas; - - const result = [ - "https://ns.adobe.com/personalization/default-content-item", - "https://ns.adobe.com/personalization/dom-action", - "https://ns.adobe.com/personalization/html-content-item", - "https://ns.adobe.com/personalization/json-content-item", - "https://ns.adobe.com/personalization/redirect-item", - ].every((schema) => personalizationSchemas.includes(schema)); - - await t.expect(result).eql(true); - - const response = JSON.parse( - getResponseBody(networkLogger.edgeEndpointLogs.requests[0]), - ); - const personalizationPayload = createResponse({ - content: response, - }).getPayloadsByType("personalization:decisions"); - - await t.expect(personalizationPayload.length).eql(1); - await flushPromiseChains(); - - return personalizationPayload; -}; - -const simulateViewChange = async (alloy, personalizationPayload) => { - // sendEvent at a view change, this shouldn't request any data, it should use the existing cache - const resultingObject = await alloy.sendEvent({ - renderDecisions: true, - xdm: { - web: { - webPageDetails: { - viewName: "products", - }, - }, - }, - }); - - const viewChangeRequest = networkLogger.edgeEndpointLogs.requests[1]; - const viewChangeRequestBody = JSON.parse(viewChangeRequest.request.body); - const event = viewChangeRequestBody.events[0]; - const query = event.query; - const web = event.xdm.web; - // eslint-disable-next-line no-underscore-dangle - const experience = event.xdm._experience; - - // assert that no personalization query was attached to the request - await t.expect(query).eql(undefined); - // assert that no personalization query was attached to the request - await t.expect(web.webPageDetails.viewName).eql("products"); - - await t - .expect(getDecisionContent("personalization-products-container-ajo")) - .eql("Welcome to AJO SPA products!"); - - // Let promises resolve so that the notification is sent. - await flushPromiseChains(); - - // check that the view change request payload contains - // the decisions that were rendered - const productsViewDecisionsMeta = getDecisionsMetaByScope( - personalizationPayload, - "products", - ); - - await t - .expect(experience.decisioning.propositions) - .eql(productsViewDecisionsMeta); - await t.expect(experience.decisioning.propositionEventType.display).eql(1); - - // assert we return the renderAttempted flag set to true - const allPropositionsWereRendered = resultingObject.propositions.every( - (proposition) => proposition.renderAttempted, - ); - - await t.expect(allPropositionsWereRendered).eql(true); -}; - -test.skip("Test C11389844: AJO SPA support", async () => { - const alloy = createAlloyProxy(); - - await alloy.configure(config); - await addContentContainer(); - - const personalizationPayload = await simulatePageLoad(alloy); - - await simulateViewChange(alloy, personalizationPayload); -}); diff --git a/packages/core/test/functional/specs/Personalization/C1234567.js b/packages/core/test/functional/specs/Personalization/C1234567.js deleted file mode 100644 index a5e9ad46e..000000000 --- a/packages/core/test/functional/specs/Personalization/C1234567.js +++ /dev/null @@ -1,711 +0,0 @@ -/* eslint-disable func-style, prefer-object-spread */ -/* -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 { ClientFunction, t, Selector } from "testcafe"; -import uuid from "../../../../src/utils/uuid.js"; -import createNetworkLogger from "../../helpers/networkLogger/index.js"; -import createFixture from "../../helpers/createFixture/index.js"; -import { - compose, - debugEnabled, -} from "../../helpers/constants/configParts/index.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; -import getBaseConfig from "../../helpers/getBaseConfig.js"; -import { TEST_PAGE as TEST_PAGE_URL } from "../../helpers/constants/url.js"; -import addHtmlToBody from "../../helpers/dom/addHtmlToBody.js"; -import { ADOBE_JOURNEY_OPTIMIZER } from "../../../../src/constants/decisionProvider.js"; -import { responseStatus } from "../../helpers/assertions/index.js"; -import flushPromiseChains from "../../helpers/flushPromiseChains.js"; - -const REASONABLE_WAIT_TIME = 250; - -const networkLogger = createNetworkLogger(); -const { edgeEndpointLogs } = networkLogger; - -const orgId = "97D1F3F459CE0AD80A495CBE@AdobeOrg"; - -const orgMainConfigMain = getBaseConfig( - orgId, - "0a106b4d-1937-4196-a64d-4a324e972459", -); -const config = compose(orgMainConfigMain, debugEnabled, { - personalizationStorageEnabled: true, -}); - -test.meta({ - ID: "C1234567", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -createFixture({ - title: "C1234567 - Content Cards", - url: `${TEST_PAGE_URL}?test=C17409728`, - requestHooks: [edgeEndpointLogs], -}); - -const testPageBody = ` -

    Content Cards

    -
      -`; - -const createMockResponse = ({ - scope = "web://aepdemo.com/", - propositionId = uuid(), - activityId = uuid(), - decisionProvider = ADOBE_JOURNEY_OPTIMIZER, - items = [], -}) => { - return { - requestId: uuid(), - handle: [ - { - payload: [ - { - id: "54671057599843051332294448941462242513", - namespace: { - code: "ECID", - }, - }, - ], - type: "identity:result", - }, - { - payload: [ - { - id: propositionId, - scope, - scopeDetails: { - decisionProvider, - correlationID: "6dae465b-9553-4fc6-b7d4-6c9979c88f21-0", - characteristics: { - eventToken: - "eyJtZXNzYWdlRXhlY3V0aW9uIjp7Im1lc3NhZ2VFeGVjdXRpb25JRCI6IlVFOkluYm91bmQiLCJtZXNzYWdlSUQiOiJmMzgxZWJhYS1kNDIyLTQxNzQtOWUzNS0yMTY3NDYwMjk5MTAiLCJtZXNzYWdlUHVibGljYXRpb25JRCI6IjZkYWU0NjViLTk1NTMtNGZjNi1iN2Q0LTZjOTk3OWM4OGYyMSIsIm1lc3NhZ2VUeXBlIjoibWFya2V0aW5nIiwiY2FtcGFpZ25JRCI6ImVhZDg5MWE0LTNjYWUtNGE1ZC05MGEzLTFkZTc0MzkwYjNkMyIsImNhbXBhaWduVmVyc2lvbklEIjoiZDhiYzk5YmMtZGRhZC00Y2MyLThlYjItYTJlMGUzY2FmNzg0IiwiY2FtcGFpZ25BY3Rpb25JRCI6IjQzNmZmM2NkLTZkZWItNDczNi04NDc1LTA3NDhhYzc4MTlkOCJ9LCJtZXNzYWdlUHJvZmlsZSI6eyJtZXNzYWdlUHJvZmlsZUlEIjoiMDg5NGYwNmYtOTkyNi00YTc2LTk4OTktYThmZjc3NWZmNTA4IiwiY2hhbm5lbCI6eyJfaWQiOiJodHRwczovL25zLmFkb2JlLmNvbS94ZG0vY2hhbm5lbHMvd2ViIiwiX3R5cGUiOiJodHRwczovL25zLmFkb2JlLmNvbS94ZG0vY2hhbm5lbC10eXBlcy93ZWIifX19", - }, - activity: { - id: activityId, - }, - }, - items: [...items], - }, - ], - type: "personalization:decisions", - eventIndex: 0, - }, - ], - }; -}; - -const getHistoricEventFromLocalStorage = ClientFunction( - (organizationId, activityId, eventType) => { - const key = `com.adobe.alloy.${organizationId.split("@")[0]}_AdobeOrg.decisioning.events`; - const data = JSON.parse(localStorage.getItem(key) || "{}"); - const events = data[eventType] || {}; - const event = events[activityId]; - return event || null; - }, -); - -test("Test C1234567: Subscribes content cards", async () => { - const surface = "web://mywebsite.com/#my-cards"; - - const mockPublishedDate = Math.ceil(new Date().getTime() / 1000) - 864000; - const mockExpiryDate = Math.ceil(new Date().getTime() / 1000) + 864000; - - const activityId = uuid(); - const propositionId = uuid(); - const itemId = uuid(); - - const responseBody = createMockResponse({ - scope: surface, - activityId, - propositionId, - items: [ - { - id: itemId, - schema: "https://ns.adobe.com/personalization/ruleset-item", - data: { - version: 1, - rules: [ - { - condition: { - definition: { - conditions: [ - { - definition: { - key: "~timestampu", - matcher: "le", - values: [mockExpiryDate], - }, - type: "matcher", - }, - { - definition: { - conditions: [ - { - definition: { - events: [ - { - "iam.eventType": "trigger", - "iam.id": activityId, - }, - ], - matcher: "ge", - value: 1, - }, - type: "historical", - }, - { - definition: { - conditions: [ - { - definition: { - key: "action", - matcher: "eq", - values: ["deposit-funds"], - }, - type: "matcher", - }, - ], - logic: "and", - }, - type: "group", - }, - ], - logic: "or", - }, - type: "group", - }, - ], - logic: "and", - }, - type: "group", - }, - consequences: [ - { - type: "schema", - detail: { - schema: - "https://ns.adobe.com/personalization/message/content-card", - data: { - expiryDate: mockExpiryDate, - publishedDate: mockPublishedDate, - meta: { - surface, - }, - content: { - shouldPinToTop: false, - imageUrl: - "https://raw.githubusercontent.com/jasonwaters/assets/master/2024/05/img_20240523_1716483354.png", - actionTitle: "View balance", - actionUrl: "https://paypal.com", - body: "Now you're ready to earn!", - title: "Funds deposited.", - }, - contentType: "application/json", - }, - id: itemId, - }, - id: itemId, - }, - ], - }, - ], - }, - }, - ], - }); - - await addHtmlToBody(testPageBody, true); - - const alloy = createAlloyProxy(); - await alloy.configure(config); - await alloy.applyResponse({ - renderDecisions: true, - responseBody, - }); - - await alloy.subscribeRulesetItems({ - surfaces: [surface], - schemas: ["https://ns.adobe.com/personalization/message/content-card"], - callback: (result, collectEvent) => { - function createContentCard(proposition, item) { - const { data = {} } = item; - const { - content = {}, - meta = {}, - publishedDate, - qualifiedDate, - displayedDate, - } = data; - - return Object.assign({}, content, { - meta, - qualifiedDate, - displayedDate, - publishedDate, - getProposition: () => proposition, - }); - } - - function extractContentCards(propositions) { - return propositions - .reduce((allItems, proposition) => { - const { items = [] } = proposition; - - return allItems.concat( - items.map((item) => createContentCard(proposition, item)), - ); - }, []) - .sort( - (a, b) => - b.qualifiedDate - a.qualifiedDate || - b.publishedDate - a.publishedDate, - ); - } - - const { propositions = [] } = result; - - if (propositions.length === 0) { - return; - } - - const contentCards = extractContentCards(propositions); - - const ul = document.getElementById("content-cards"); - let html = ""; - contentCards.forEach((contentCard, idx) => { - html += `
    • Item Image
      ${contentCard.title}

      ${contentCard.body}

    • `; - }); - ul.innerHTML = html; - - collectEvent("display", propositions); - - ul.addEventListener("click", (evt) => { - const li = evt.target.closest("li"); - if (!li) { - return; - } - collectEvent("interact", [ - contentCards[li.dataset.idx].getProposition(), - ]); - }); - }, - }); - - await alloy.evaluateRulesets({ - renderDecisions: true, - personalization: { - decisionContext: { - action: "deposit-funds", - }, - }, - }); - - // allow async storage of event-history operations to complete - await flushPromiseChains(); - - // validate display event sent (network-level assertion) - await responseStatus(edgeEndpointLogs.requests, [200, 204, 207]); - await flushPromiseChains(); - await t.expect(edgeEndpointLogs.count(() => true)).eql(1); - const displayRequest = edgeEndpointLogs.requests[0]; - const displayBody = JSON.parse(displayRequest.request.body); - await t - .expect(displayBody.events[0].xdm.eventType) - .eql("decisioning.propositionDisplay"); - await t - .expect( - // eslint-disable-next-line no-underscore-dangle - displayBody.events[0].xdm._experience.decisioning.propositions.length, - ) - .gt(0); - - await t.click("#content-card-0"); - await t.wait(REASONABLE_WAIT_TIME); - - await flushPromiseChains(); - - // validate interact event sent (network-level assertion) - await responseStatus(edgeEndpointLogs.requests, [200, 204, 207]); - await flushPromiseChains(); - const interactRequest = edgeEndpointLogs.requests[1]; - const interactBody = JSON.parse(interactRequest.request.body); - await t - .expect(interactBody.events[0].xdm.eventType) - .eql("decisioning.propositionInteract"); - await t - .expect( - // eslint-disable-next-line no-underscore-dangle - interactBody.events[0].xdm._experience.decisioning.propositions.length, - ) - .gt(0); - - // validate total requests - await t.expect(edgeEndpointLogs.count(() => true)).eql(2); -}); - -test("Test C1234567: Content card expiration", async () => { - const surface = "web://mywebsite.com/#expired-cards"; - - const mockPublishedDate = Math.ceil(new Date().getTime() / 1000) - 864000; - const mockExpiryDate = Math.ceil(new Date().getTime() / 1000) - 3600; // 1 hour ago - - const activityId = uuid(); - const propositionId = uuid(); - const itemId = uuid(); - - const responseBody = createMockResponse({ - scope: surface, - activityId, - propositionId, - items: [ - { - id: itemId, - schema: "https://ns.adobe.com/personalization/ruleset-item", - data: { - version: 1, - rules: [ - { - condition: { - definition: { - conditions: [ - { - definition: { - key: "~timestampu", - matcher: "le", - values: [mockExpiryDate], - }, - type: "matcher", - }, - ], - logic: "and", - }, - type: "group", - }, - consequences: [ - { - type: "schema", - detail: { - schema: - "https://ns.adobe.com/personalization/message/content-card", - data: { - expiryDate: mockExpiryDate, - publishedDate: mockPublishedDate, - meta: { - surface, - }, - content: { - shouldPinToTop: false, - imageUrl: - "https://raw.githubusercontent.com/jasonwaters/assets/master/2024/05/img_20240523_1716483354.png", - actionTitle: "Expired Action", - actionUrl: "https://paypal.com", - body: "This card should not be displayed", - title: "Expired Card", - }, - contentType: "application/json", - }, - id: itemId, - }, - id: itemId, - }, - ], - }, - ], - }, - }, - ], - }); - - await addHtmlToBody(testPageBody, true); - - const alloy = createAlloyProxy(); - await alloy.configure(config); - await alloy.applyResponse({ - renderDecisions: true, - responseBody, - }); - - let displayEventCalled = false; - - await alloy.subscribeRulesetItems({ - surfaces: [surface], - schemas: ["https://ns.adobe.com/personalization/message/content-card"], - callback: (result, collectEvent) => { - function createContentCard(proposition, item) { - const { data = {} } = item; - const { - content = {}, - meta = {}, - publishedDate, - qualifiedDate, - displayedDate, - } = data; - - return Object.assign({}, content, { - meta, - qualifiedDate, - displayedDate, - publishedDate, - getProposition: () => proposition, - }); - } - - function extractContentCards(propositions) { - return propositions - .reduce((allItems, proposition) => { - const { items = [] } = proposition; - return allItems.concat( - items.map((item) => createContentCard(proposition, item)), - ); - }, []) - .sort( - (a, b) => - b.qualifiedDate - a.qualifiedDate || - b.publishedDate - a.publishedDate, - ); - } - - const { propositions = [] } = result; - const contentCards = extractContentCards(propositions); - - const ul = document.getElementById("content-cards"); - let html = ""; - contentCards.forEach((contentCard, idx) => { - html += `
    • Item Image
      ${contentCard.title}

      ${contentCard.body}

    • `; - }); - ul.innerHTML = html; - - if (contentCards.length > 0) { - displayEventCalled = true; - collectEvent("display", propositions); - } - }, - }); - - await alloy.evaluateRulesets({ - renderDecisions: true, - personalization: { - decisionContext: {}, - }, - }); - - // Assert that no content cards are rendered - await t.expect(Selector("#content-cards").childElementCount).eql(0); - - // Verify that no display event was called - await t.expect(displayEventCalled).eql(false); - - // Verify that no network requests were made for display events - await t.expect(edgeEndpointLogs.count(() => true)).eql(0); -}); - -test("Test C1234567: Content card interaction tracking", async () => { - const surface = "web://mywebsite.com/#interaction-tracking"; - - const mockPublishedDate = Math.ceil(new Date().getTime() / 1000) - 864000; - const mockExpiryDate = Math.ceil(new Date().getTime() / 1000) + 864000; - - const activityId = uuid(); - const propositionId = uuid(); - const itemId = uuid(); - - const responseBody = createMockResponse({ - scope: surface, - activityId, - propositionId, - items: [ - { - id: itemId, - schema: "https://ns.adobe.com/personalization/ruleset-item", - data: { - version: 1, - rules: [ - { - condition: { - definition: { - conditions: [ - { - definition: { - key: "~timestampu", - matcher: "le", - values: [mockExpiryDate], - }, - type: "matcher", - }, - ], - logic: "and", - }, - type: "group", - }, - consequences: [ - { - type: "schema", - detail: { - schema: - "https://ns.adobe.com/personalization/message/content-card", - data: { - expiryDate: mockExpiryDate, - publishedDate: mockPublishedDate, - meta: { - surface, - }, - content: { - shouldPinToTop: false, - imageUrl: - "https://raw.githubusercontent.com/jasonwaters/assets/master/2024/05/img_20240523_1716483354.png", - actionTitle: "Expired Action", - actionUrl: "https://paypal.com", - body: "This card should not be displayed", - title: "Expired Card", - }, - contentType: "application/json", - }, - id: itemId, - }, - id: itemId, - }, - ], - }, - ], - }, - }, - ], - }); - - await addHtmlToBody(testPageBody, true); - - const alloy = createAlloyProxy(); - await alloy.configure(config); - await alloy.applyResponse({ - renderDecisions: true, - responseBody, - }); - - await alloy.subscribeRulesetItems({ - surfaces: [surface], - schemas: ["https://ns.adobe.com/personalization/message/content-card"], - callback: (result, collectEvent) => { - function createContentCard(proposition, item) { - const { data = {} } = item; - const { - content = {}, - meta = {}, - publishedDate, - qualifiedDate, - displayedDate, - } = data; - - return Object.assign({}, content, { - meta, - qualifiedDate, - displayedDate, - publishedDate, - getProposition: () => proposition, - }); - } - - function extractContentCards(propositions) { - return propositions - .reduce((allItems, proposition) => { - const { items = [] } = proposition; - return allItems.concat( - items.map((item) => createContentCard(proposition, item)), - ); - }, []) - .sort( - (a, b) => - b.qualifiedDate - a.qualifiedDate || - b.publishedDate - a.publishedDate, - ); - } - - const { propositions = [] } = result; - const contentCards = extractContentCards(propositions); - - const ul = document.getElementById("content-cards"); - let html = ""; - contentCards.forEach((contentCard, idx) => { - html += `
    • Item Image
      ${contentCard.title}

      ${contentCard.body}

      ${contentCard.actionTitle}
    • `; - }); - ul.innerHTML = html; - - collectEvent("display", propositions); - - ul.addEventListener("click", (evt) => { - const li = evt.target.closest("li"); - if (!li) { - return; - } - collectEvent("interact", [ - contentCards[li.dataset.idx].getProposition(), - ]); - }); - }, - }); - - await alloy.evaluateRulesets({ - renderDecisions: true, - personalization: { - decisionContext: {}, - }, - }); - - // Verify that the content card is rendered - await t.expect(Selector("#content-cards").childElementCount).eql(1); - - // Verify display event - const displayEvent = await getHistoricEventFromLocalStorage( - orgId, - activityId, - "display", - ); - - if (displayEvent !== null) { - await t.expect(displayEvent.count).eql(1); - } - - // Simulate user interaction (click on the action link) - await t.click("#content-card-0 .action-link"); - await t.wait(REASONABLE_WAIT_TIME); - - // Verify interact event - const interactEvent = await getHistoricEventFromLocalStorage( - orgId, - activityId, - "interact", - ); - - if (interactEvent !== null) { - await t.expect(interactEvent.count).eql(1); - } - - // Validate network requests - await responseStatus(edgeEndpointLogs.requests, [200, 204, 207]); - const requestCount = await edgeEndpointLogs.count(() => true); - - // Final assertions - await t - .expect(requestCount) - .gte(1, "At least one network request should be made"); - if (displayEvent !== null) { - await t - .expect(displayEvent.count) - .eql(1, "Display event should be recorded"); - } - if (interactEvent !== null) { - await t - .expect(interactEvent.count) - .eql(1, "Interact event should be recorded"); - } -}); diff --git a/packages/core/test/functional/specs/Personalization/C14286730.js b/packages/core/test/functional/specs/Personalization/C14286730.js deleted file mode 100644 index 4c13085c6..000000000 --- a/packages/core/test/functional/specs/Personalization/C14286730.js +++ /dev/null @@ -1,90 +0,0 @@ -/* -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 } from "testcafe"; -import createNetworkLogger from "../../helpers/networkLogger/index.js"; -import { responseStatus } from "../../helpers/assertions/index.js"; -import createFixture from "../../helpers/createFixture/index.js"; -import { - compose, - orgMainConfigMain, - debugEnabled, - clickCollectionEventGroupingDisabled, -} from "../../helpers/constants/configParts/index.js"; -import { TEST_PAGE as TEST_PAGE_URL } from "../../helpers/constants/url.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; -import addHtmlToBody from "../../helpers/dom/addHtmlToBody.js"; - -const networkLogger = createNetworkLogger(); -const config = compose( - orgMainConfigMain, - debugEnabled, - clickCollectionEventGroupingDisabled, -); - -createFixture({ - title: "C14286730: Target SPA click interaction includes viewName", - requestHooks: [networkLogger.edgeEndpointLogs], - url: `${TEST_PAGE_URL}?test=C14286730`, -}); - -test.meta({ - ID: "C28755", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -test("Test C14286730: Target SPA click interaction includes viewName", async () => { - const alloy = createAlloyProxy(); - await alloy.configure(config); - - await addHtmlToBody( - `
      Products
      `, - ); - await alloy.sendEvent({ - renderDecisions: true, - xdm: { - web: { - webPageDetails: { - viewName: "products", - }, - }, - }, - }); - - await responseStatus(networkLogger.edgeEndpointLogs.requests, [200, 207]); - - // await t.expect(networkLogger.edgeEndpointLogs.count(() => true)).eql(2); - - await t.click(".clickme"); - - // await t.expect(networkLogger.edgeEndpointLogs.count(() => true)).eql(3); - - const displayNotification = JSON.parse( - networkLogger.edgeEndpointLogs.requests[1].request.body, - ); - - // TODO: Testcafe no longer captures the request body for sendBeacon requests. - // We could enhance this test to use Assurance to verify the request body. - // const interactNotification = JSON.parse( - // networkLogger.edgeEndpointLogs.requests[2].request.body, - // ); - // - await t - .expect(displayNotification.events[0].xdm.web.webPageDetails.viewName) - .eql("products"); - - // TODO: Testcafe no longer captures the request body for sendBeacon requests. - // We could enhance this test to use Assurance to verify the request body. - // await t - // .expect(interactNotification.events[0].xdm.web.webPageDetails.viewName) - // .eql("products"); -}); diff --git a/packages/core/test/functional/specs/Personalization/C14299419.js b/packages/core/test/functional/specs/Personalization/C14299419.js deleted file mode 100644 index 1260bef85..000000000 --- a/packages/core/test/functional/specs/Personalization/C14299419.js +++ /dev/null @@ -1,47 +0,0 @@ -/* -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, Selector } from "testcafe"; -import createFixture from "../../helpers/createFixture/index.js"; -import { - compose, - orgMainConfigMain, - debugEnabled, -} from "../../helpers/constants/configParts/index.js"; -import { TEST_PAGE as TEST_PAGE_URL } from "../../helpers/constants/url.js"; -import createAlloyProxy from "../../helpers/createAlloyProxy.js"; -import addHtmlToHeader from "../../helpers/dom/addHtmlToHeader.js"; - -const config = compose(orgMainConfigMain, debugEnabled); - -createFixture({ - title: - "C14299419: Prehiding style is removed when no personalization payload is returned", - url: `${TEST_PAGE_URL}?test=C14299419`, -}); - -test.meta({ - ID: "C14299419", - SEVERITY: "P0", - TEST_RUN: "Regression", -}); - -test("Test C14299419: Prehiding style is removed when no personalization payload is returned", async () => { - await addHtmlToHeader( - `