From c133396c733238a7a460df166f4346f2bd5092fa Mon Sep 17 00:00:00 2001 From: Carter McBride <18412686+carterworks@users.noreply.github.com> Date: Fri, 12 Jun 2026 11:55:47 -0600 Subject: [PATCH 01/12] test(integration): migrate logging functional specs to Vitest+Playwright+MSW --- .../integration/specs/Logging/logging.spec.js | 160 ++++++++++++++++++ 1 file changed, 160 insertions(+) create mode 100644 packages/browser/test/integration/specs/Logging/logging.spec.js diff --git a/packages/browser/test/integration/specs/Logging/logging.spec.js b/packages/browser/test/integration/specs/Logging/logging.spec.js new file mode 100644 index 000000000..62804d231 --- /dev/null +++ b/packages/browser/test/integration/specs/Logging/logging.spec.js @@ -0,0 +1,160 @@ +/* +Copyright 2026 Adobe. All rights reserved. +This file is licensed to you under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. You may obtain a copy +of the License at http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under +the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES 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, + expect, + describe, + vi, + beforeEach, + afterEach, +} from "../../helpers/testsSetup/extend.js"; +import { test as vitestTest } from "vitest"; +import { sendEventHandler } from "../../helpers/mswjs/handlers.js"; +import alloyConfig from "../../helpers/alloy/config.js"; +import searchForLogMessage from "../../helpers/utils/searchForLogMessage.js"; +import { withTemporaryUrl } from "../../helpers/utils/location.js"; +import setupBaseCode from "../../helpers/alloy/setupBaseCode.js"; +import setupAlloy from "../../helpers/alloy/setup.js"; +import cleanAlloy from "../../helpers/alloy/clean.js"; + +describe("Toggle logging through configuration (C2583)", () => { + let consoleSpy; + + beforeEach(() => { + consoleSpy = vi.spyOn(console, "info"); + }); + + afterEach(() => { + consoleSpy.mockRestore(); + }); + + test("logs sendEvent when debugEnabled is true", async ({ alloy, worker }) => { + worker.use(sendEventHandler); + await alloy("configure", { ...alloyConfig, debugEnabled: true }); + await alloy("sendEvent"); + expect(searchForLogMessage(consoleSpy, "Executing sendEvent command")).toBe( + true, + ); + }); + + test("does not log sendEvent when debugEnabled is false", async ({ + alloy, + worker, + }) => { + worker.use(sendEventHandler); + await alloy("configure", { ...alloyConfig, debugEnabled: false }); + await alloy("sendEvent"); + expect(searchForLogMessage(consoleSpy, "Executing sendEvent command")).toBe( + false, + ); + }); +}); + +describe("Toggle logging through setDebug command (C2584)", () => { + let consoleSpy; + + beforeEach(() => { + consoleSpy = vi.spyOn(console, "info"); + }); + + afterEach(() => { + consoleSpy.mockRestore(); + }); + + test("enables logging when setDebug called with enabled: true", async ({ + alloy, + }) => { + await alloy("configure", alloyConfig); + await alloy("setDebug", { enabled: true }); + await alloy("getLibraryInfo"); + expect( + searchForLogMessage(consoleSpy, "Executing getLibraryInfo command"), + ).toBe(true); + }); + + test("disables logging when setDebug called with enabled: false after being enabled", async ({ + alloy, + }) => { + await alloy("configure", { ...alloyConfig, debugEnabled: true }); + await alloy("setDebug", { enabled: false }); + consoleSpy.mockClear(); + await alloy("getLibraryInfo"); + expect( + searchForLogMessage(consoleSpy, "Executing getLibraryInfo command"), + ).toBe(false); + }); +}); + +describe("Toggle logging through querystring parameter (C2586)", () => { + // This test sets alloy_debug=true in the URL before calling configure + // so alloy reads the param during initialization + vitestTest( + "enables logging when alloy_debug=true is in the URL at configure time", + async () => { + const consoleSpy = vi.spyOn(console, "info"); + try { + await withTemporaryUrl(async ({ currentHref, applyUrl }) => { + const url = new URL(currentHref); + url.searchParams.set("alloy_debug", "true"); + applyUrl(url); + + await setupBaseCode(); + const alloy = await setupAlloy(); + + await alloy("configure", alloyConfig); + await alloy("getLibraryInfo"); + + expect( + searchForLogMessage( + consoleSpy, + "Executing getLibraryInfo command", + ), + ).toBe(true); + + cleanAlloy(); + }); + } finally { + consoleSpy.mockRestore(); + } + }, + ); +}); + +describe("Logged objects can be stringified (C532204)", () => { + test("does not throw when console methods call String() on arguments", async ({ + alloy, + worker, + }) => { + worker.use(sendEventHandler); + + const originals = {}; + ["log", "info", "warn", "error"].forEach((methodName) => { + originals[methodName] = console[methodName]; + const orig = console[methodName]; + // eslint-disable-next-line no-console + console[methodName] = (...args) => { + args.forEach((arg) => String(arg)); + orig.apply(console, args); + }; + }); + + try { + await alloy("configure", { ...alloyConfig, debugEnabled: true }); + await alloy("sendEvent"); + } finally { + ["log", "info", "warn", "error"].forEach((methodName) => { + // eslint-disable-next-line no-console + console[methodName] = originals[methodName]; + }); + } + }); +}); From 28d3d32c28caabd4afffc7bd69b6227c0a2dda32 Mon Sep 17 00:00:00 2001 From: Carter McBride <18412686+carterworks@users.noreply.github.com> Date: Fri, 12 Jun 2026 12:25:55 -0600 Subject: [PATCH 02/12] chore: apply prettier and eslint formatting Co-Authored-By: Claude Sonnet 4.6 --- .../test/integration/specs/Logging/logging.spec.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/browser/test/integration/specs/Logging/logging.spec.js b/packages/browser/test/integration/specs/Logging/logging.spec.js index 62804d231..a52bb065d 100644 --- a/packages/browser/test/integration/specs/Logging/logging.spec.js +++ b/packages/browser/test/integration/specs/Logging/logging.spec.js @@ -37,7 +37,10 @@ describe("Toggle logging through configuration (C2583)", () => { consoleSpy.mockRestore(); }); - test("logs sendEvent when debugEnabled is true", async ({ alloy, worker }) => { + test("logs sendEvent when debugEnabled is true", async ({ + alloy, + worker, + }) => { worker.use(sendEventHandler); await alloy("configure", { ...alloyConfig, debugEnabled: true }); await alloy("sendEvent"); @@ -114,10 +117,7 @@ describe("Toggle logging through querystring parameter (C2586)", () => { await alloy("getLibraryInfo"); expect( - searchForLogMessage( - consoleSpy, - "Executing getLibraryInfo command", - ), + searchForLogMessage(consoleSpy, "Executing getLibraryInfo command"), ).toBe(true); cleanAlloy(); From cc99ac86b4f926098b54fa6a21ec19cc546a9b8c Mon Sep 17 00:00:00 2001 From: Carter McBride <18412686+carterworks@users.noreply.github.com> Date: Tue, 16 Jun 2026 08:28:56 -0600 Subject: [PATCH 03/12] Use extended test instead of raw vitest --- .../integration/specs/Logging/logging.spec.js | 52 +++++++++---------- 1 file changed, 24 insertions(+), 28 deletions(-) diff --git a/packages/browser/test/integration/specs/Logging/logging.spec.js b/packages/browser/test/integration/specs/Logging/logging.spec.js index a52bb065d..03df1c3f1 100644 --- a/packages/browser/test/integration/specs/Logging/logging.spec.js +++ b/packages/browser/test/integration/specs/Logging/logging.spec.js @@ -17,7 +17,6 @@ import { beforeEach, afterEach, } from "../../helpers/testsSetup/extend.js"; -import { test as vitestTest } from "vitest"; import { sendEventHandler } from "../../helpers/mswjs/handlers.js"; import alloyConfig from "../../helpers/alloy/config.js"; import searchForLogMessage from "../../helpers/utils/searchForLogMessage.js"; @@ -100,33 +99,30 @@ describe("Toggle logging through setDebug command (C2584)", () => { describe("Toggle logging through querystring parameter (C2586)", () => { // This test sets alloy_debug=true in the URL before calling configure // so alloy reads the param during initialization - vitestTest( - "enables logging when alloy_debug=true is in the URL at configure time", - async () => { - const consoleSpy = vi.spyOn(console, "info"); - try { - await withTemporaryUrl(async ({ currentHref, applyUrl }) => { - const url = new URL(currentHref); - url.searchParams.set("alloy_debug", "true"); - applyUrl(url); - - await setupBaseCode(); - const alloy = await setupAlloy(); - - await alloy("configure", alloyConfig); - await alloy("getLibraryInfo"); - - expect( - searchForLogMessage(consoleSpy, "Executing getLibraryInfo command"), - ).toBe(true); - - cleanAlloy(); - }); - } finally { - consoleSpy.mockRestore(); - } - }, - ); + test("enables logging when alloy_debug=true is in the URL at configure time", async () => { + const consoleSpy = vi.spyOn(console, "info"); + try { + await withTemporaryUrl(async ({ currentHref, applyUrl }) => { + const url = new URL(currentHref); + url.searchParams.set("alloy_debug", "true"); + applyUrl(url); + + await setupBaseCode(); + const alloy = await setupAlloy(); + + await alloy("configure", alloyConfig); + await alloy("getLibraryInfo"); + + expect( + searchForLogMessage(consoleSpy, "Executing getLibraryInfo command"), + ).toBe(true); + + cleanAlloy(); + }); + } finally { + consoleSpy.mockRestore(); + } + }); }); describe("Logged objects can be stringified (C532204)", () => { From 4a03be627d9e8949217bca7598dcadee0a562d5a Mon Sep 17 00:00:00 2001 From: Carter McBride <18412686+carterworks@users.noreply.github.com> Date: Tue, 16 Jun 2026 08:30:34 -0600 Subject: [PATCH 04/12] Add comment about reason for test --- .../browser/test/integration/specs/Logging/logging.spec.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/browser/test/integration/specs/Logging/logging.spec.js b/packages/browser/test/integration/specs/Logging/logging.spec.js index 03df1c3f1..5936181e7 100644 --- a/packages/browser/test/integration/specs/Logging/logging.spec.js +++ b/packages/browser/test/integration/specs/Logging/logging.spec.js @@ -126,6 +126,12 @@ describe("Toggle logging through querystring parameter (C2586)", () => { }); describe("Logged objects can be stringified (C532204)", () => { + /* + * 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 + */ test("does not throw when console methods call String() on arguments", async ({ alloy, worker, From 9fcc4447e3910f451dd2c603f73a2e61dac2a9ca Mon Sep 17 00:00:00 2001 From: Carter McBride <18412686+carterworks@users.noreply.github.com> Date: Tue, 16 Jun 2026 08:35:07 -0600 Subject: [PATCH 05/12] test(logging): assert console methods were called in C532204 --- .../browser/test/integration/specs/Logging/logging.spec.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/browser/test/integration/specs/Logging/logging.spec.js b/packages/browser/test/integration/specs/Logging/logging.spec.js index 5936181e7..f53f14ed4 100644 --- a/packages/browser/test/integration/specs/Logging/logging.spec.js +++ b/packages/browser/test/integration/specs/Logging/logging.spec.js @@ -139,11 +139,13 @@ describe("Logged objects can be stringified (C532204)", () => { worker.use(sendEventHandler); const originals = {}; + let callCount = 0; ["log", "info", "warn", "error"].forEach((methodName) => { originals[methodName] = console[methodName]; const orig = console[methodName]; // eslint-disable-next-line no-console console[methodName] = (...args) => { + callCount++; args.forEach((arg) => String(arg)); orig.apply(console, args); }; @@ -158,5 +160,7 @@ describe("Logged objects can be stringified (C532204)", () => { console[methodName] = originals[methodName]; }); } + + expect(callCount).toBeGreaterThan(0); }); }); From a5c827b187bbde8d98c6ec536dfa88777839c0bc Mon Sep 17 00:00:00 2001 From: Carter McBride <18412686+carterworks@users.noreply.github.com> Date: Tue, 16 Jun 2026 08:38:29 -0600 Subject: [PATCH 06/12] test(logging): consolidate consoleSpy setup and use vi.spyOn in C532204 --- .../integration/specs/Logging/logging.spec.js | 49 ++++++------------- 1 file changed, 15 insertions(+), 34 deletions(-) diff --git a/packages/browser/test/integration/specs/Logging/logging.spec.js b/packages/browser/test/integration/specs/Logging/logging.spec.js index f53f14ed4..b44a01fb3 100644 --- a/packages/browser/test/integration/specs/Logging/logging.spec.js +++ b/packages/browser/test/integration/specs/Logging/logging.spec.js @@ -25,17 +25,15 @@ import setupBaseCode from "../../helpers/alloy/setupBaseCode.js"; import setupAlloy from "../../helpers/alloy/setup.js"; import cleanAlloy from "../../helpers/alloy/clean.js"; -describe("Toggle logging through configuration (C2583)", () => { - let consoleSpy; - - beforeEach(() => { - consoleSpy = vi.spyOn(console, "info"); - }); - - afterEach(() => { - consoleSpy.mockRestore(); - }); +let consoleSpy; +beforeEach(() => { + consoleSpy = vi.spyOn(console, "info"); +}); +afterEach(() => { + consoleSpy.mockRestore(); +}); +describe("Toggle logging through configuration (C2583)", () => { test("logs sendEvent when debugEnabled is true", async ({ alloy, worker, @@ -62,16 +60,6 @@ describe("Toggle logging through configuration (C2583)", () => { }); describe("Toggle logging through setDebug command (C2584)", () => { - let consoleSpy; - - beforeEach(() => { - consoleSpy = vi.spyOn(console, "info"); - }); - - afterEach(() => { - consoleSpy.mockRestore(); - }); - test("enables logging when setDebug called with enabled: true", async ({ alloy, }) => { @@ -138,29 +126,22 @@ describe("Logged objects can be stringified (C532204)", () => { }) => { worker.use(sendEventHandler); - const originals = {}; - let callCount = 0; - ["log", "info", "warn", "error"].forEach((methodName) => { - originals[methodName] = console[methodName]; - const orig = console[methodName]; - // eslint-disable-next-line no-console - console[methodName] = (...args) => { - callCount++; + const spies = ["log", "info", "warn", "error"].map((methodName) => { + const through = console[methodName].bind(console); + return vi.spyOn(console, methodName).mockImplementation((...args) => { args.forEach((arg) => String(arg)); - orig.apply(console, args); - }; + through(...args); + }); }); try { await alloy("configure", { ...alloyConfig, debugEnabled: true }); await alloy("sendEvent"); } finally { - ["log", "info", "warn", "error"].forEach((methodName) => { - // eslint-disable-next-line no-console - console[methodName] = originals[methodName]; - }); + spies.forEach((spy) => spy.mockRestore()); } + const callCount = spies.reduce((sum, spy) => sum + spy.mock.calls.length, 0); expect(callCount).toBeGreaterThan(0); }); }); From 1a786e5c339cd6ec51d09636a87b761bb43ae560 Mon Sep 17 00:00:00 2001 From: Carter McBride <18412686+carterworks@users.noreply.github.com> Date: Tue, 16 Jun 2026 08:43:24 -0600 Subject: [PATCH 07/12] test(logging): generalize searchForLogMessage to scan all args --- .../test/integration/helpers/utils/searchForLogMessage.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/browser/test/integration/helpers/utils/searchForLogMessage.js b/packages/browser/test/integration/helpers/utils/searchForLogMessage.js index 374369fad..0bbbdfacf 100644 --- a/packages/browser/test/integration/helpers/utils/searchForLogMessage.js +++ b/packages/browser/test/integration/helpers/utils/searchForLogMessage.js @@ -11,7 +11,6 @@ governing permissions and limitations under the License. */ export default (spy, searchMessage) => - spy.mock.calls.some( - ([, logMessage]) => - typeof logMessage === "string" && logMessage.includes(searchMessage), + spy.mock.calls.some((args) => + args.some((arg) => typeof arg === "string" && arg.includes(searchMessage)), ); From 8a4926468dbce0f48e51219723f155922b5cfe46 Mon Sep 17 00:00:00 2001 From: Carter McBride <18412686+carterworks@users.noreply.github.com> Date: Tue, 16 Jun 2026 08:44:32 -0600 Subject: [PATCH 08/12] Delete migrated logging tests --- .../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 ------------------- 4 files changed, 192 deletions(-) delete mode 100644 packages/browser/test/functional/specs/Logging/C2583.js delete mode 100644 packages/browser/test/functional/specs/Logging/C2584.js delete mode 100644 packages/browser/test/functional/specs/Logging/C2586.js delete mode 100644 packages/browser/test/functional/specs/Logging/C532204.js diff --git a/packages/browser/test/functional/specs/Logging/C2583.js b/packages/browser/test/functional/specs/Logging/C2583.js deleted file mode 100644 index e9dbd6b86..000000000 --- a/packages/browser/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/browser/test/functional/specs/Logging/C2584.js b/packages/browser/test/functional/specs/Logging/C2584.js deleted file mode 100644 index 3d49d7438..000000000 --- a/packages/browser/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/browser/test/functional/specs/Logging/C2586.js b/packages/browser/test/functional/specs/Logging/C2586.js deleted file mode 100644 index 1187f04b9..000000000 --- a/packages/browser/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/browser/test/functional/specs/Logging/C532204.js b/packages/browser/test/functional/specs/Logging/C532204.js deleted file mode 100644 index ac7cea20d..000000000 --- a/packages/browser/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(); -}); From bf685d4e081d18dc8d57943dd0acef51adb6e773 Mon Sep 17 00:00:00 2001 From: Carter McBride <18412686+carterworks@users.noreply.github.com> Date: Tue, 16 Jun 2026 08:56:15 -0600 Subject: [PATCH 09/12] test(logging): remove redundant cleanAlloy call from C2586 --- .../test/integration/specs/Logging/logging.spec.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/browser/test/integration/specs/Logging/logging.spec.js b/packages/browser/test/integration/specs/Logging/logging.spec.js index b44a01fb3..34b03c60c 100644 --- a/packages/browser/test/integration/specs/Logging/logging.spec.js +++ b/packages/browser/test/integration/specs/Logging/logging.spec.js @@ -23,7 +23,6 @@ import searchForLogMessage from "../../helpers/utils/searchForLogMessage.js"; import { withTemporaryUrl } from "../../helpers/utils/location.js"; import setupBaseCode from "../../helpers/alloy/setupBaseCode.js"; import setupAlloy from "../../helpers/alloy/setup.js"; -import cleanAlloy from "../../helpers/alloy/clean.js"; let consoleSpy; beforeEach(() => { @@ -104,8 +103,6 @@ describe("Toggle logging through querystring parameter (C2586)", () => { expect( searchForLogMessage(consoleSpy, "Executing getLibraryInfo command"), ).toBe(true); - - cleanAlloy(); }); } finally { consoleSpy.mockRestore(); @@ -141,7 +138,10 @@ describe("Logged objects can be stringified (C532204)", () => { spies.forEach((spy) => spy.mockRestore()); } - const callCount = spies.reduce((sum, spy) => sum + spy.mock.calls.length, 0); + const callCount = spies.reduce( + (sum, spy) => sum + spy.mock.calls.length, + 0, + ); expect(callCount).toBeGreaterThan(0); }); }); From 71c95799227aef4600bb396deef35e978b9efb0c Mon Sep 17 00:00:00 2001 From: Carter McBride <18412686+carterworks@users.noreply.github.com> Date: Tue, 16 Jun 2026 09:03:14 -0600 Subject: [PATCH 10/12] test(logging): fix C532204 console spy recursion and call count The C532204 test re-spied console.info, which the file's beforeEach had already spied. vi.spyOn returns the existing spy, so binding `through` to console.info bound it to that same spy and forwarding looped back through the mock implementation (stack overflow). Forward to console methods captured before beforeEach installs the spy instead. Also snapshot the call count inside the try block: mockRestore in the finally clears mock.calls, so reading it afterward always saw 0. --- .../integration/specs/Logging/logging.spec.js | 27 ++++++++++++------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/packages/browser/test/integration/specs/Logging/logging.spec.js b/packages/browser/test/integration/specs/Logging/logging.spec.js index 34b03c60c..48a0b02a9 100644 --- a/packages/browser/test/integration/specs/Logging/logging.spec.js +++ b/packages/browser/test/integration/specs/Logging/logging.spec.js @@ -24,6 +24,16 @@ import { withTemporaryUrl } from "../../helpers/utils/location.js"; import setupBaseCode from "../../helpers/alloy/setupBaseCode.js"; import setupAlloy from "../../helpers/alloy/setup.js"; +// Captured before beforeEach spies on console.info, so forwarding from a +// re-spied method doesn't loop back through the spy. See C532204 below. +const originalConsole = ["log", "info", "warn", "error"].reduce( + (acc, methodName) => { + acc[methodName] = console[methodName].bind(console); + return acc; + }, + {}, +); + let consoleSpy; beforeEach(() => { consoleSpy = vi.spyOn(console, "info"); @@ -123,25 +133,22 @@ describe("Logged objects can be stringified (C532204)", () => { }) => { worker.use(sendEventHandler); - const spies = ["log", "info", "warn", "error"].map((methodName) => { - const through = console[methodName].bind(console); - return vi.spyOn(console, methodName).mockImplementation((...args) => { + const spies = ["log", "info", "warn", "error"].map((methodName) => + vi.spyOn(console, methodName).mockImplementation((...args) => { args.forEach((arg) => String(arg)); - through(...args); - }); - }); + originalConsole[methodName](...args); + }), + ); + let callCount; try { await alloy("configure", { ...alloyConfig, debugEnabled: true }); await alloy("sendEvent"); + callCount = spies.reduce((sum, spy) => sum + spy.mock.calls.length, 0); } finally { spies.forEach((spy) => spy.mockRestore()); } - const callCount = spies.reduce( - (sum, spy) => sum + spy.mock.calls.length, - 0, - ); expect(callCount).toBeGreaterThan(0); }); }); From 1a47ae5fe88dc2dc09cab849b39d37fe1463bc32 Mon Sep 17 00:00:00 2001 From: Carter McBride <18412686+carterworks@users.noreply.github.com> Date: Tue, 16 Jun 2026 09:09:34 -0600 Subject: [PATCH 11/12] test(logging): silence console spies to keep reporter output clean The console spies forwarded to the real console by default, so alloy's debug logging spammed the test reporter. Stub them with a no-op implementation: searchForLogMessage reads spy.mock.calls, not actual output, so assertions are unaffected. This also drops the originalConsole forwarding in C532204 (and with it the recursion risk it guarded against). --- .../integration/specs/Logging/logging.spec.js | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/packages/browser/test/integration/specs/Logging/logging.spec.js b/packages/browser/test/integration/specs/Logging/logging.spec.js index 48a0b02a9..0d8233cfa 100644 --- a/packages/browser/test/integration/specs/Logging/logging.spec.js +++ b/packages/browser/test/integration/specs/Logging/logging.spec.js @@ -24,19 +24,11 @@ import { withTemporaryUrl } from "../../helpers/utils/location.js"; import setupBaseCode from "../../helpers/alloy/setupBaseCode.js"; import setupAlloy from "../../helpers/alloy/setup.js"; -// Captured before beforeEach spies on console.info, so forwarding from a -// re-spied method doesn't loop back through the spy. See C532204 below. -const originalConsole = ["log", "info", "warn", "error"].reduce( - (acc, methodName) => { - acc[methodName] = console[methodName].bind(console); - return acc; - }, - {}, -); - let consoleSpy; beforeEach(() => { - consoleSpy = vi.spyOn(console, "info"); + // Don't forward to the real console; the spy still records calls for + // assertions, but the reporter output stays clean. + consoleSpy = vi.spyOn(console, "info").mockImplementation(() => {}); }); afterEach(() => { consoleSpy.mockRestore(); @@ -97,7 +89,7 @@ describe("Toggle logging through querystring parameter (C2586)", () => { // This test sets alloy_debug=true in the URL before calling configure // so alloy reads the param during initialization test("enables logging when alloy_debug=true is in the URL at configure time", async () => { - const consoleSpy = vi.spyOn(console, "info"); + const consoleSpy = vi.spyOn(console, "info").mockImplementation(() => {}); try { await withTemporaryUrl(async ({ currentHref, applyUrl }) => { const url = new URL(currentHref); @@ -136,7 +128,6 @@ describe("Logged objects can be stringified (C532204)", () => { const spies = ["log", "info", "warn", "error"].map((methodName) => vi.spyOn(console, methodName).mockImplementation((...args) => { args.forEach((arg) => String(arg)); - originalConsole[methodName](...args); }), ); From 30cac6a6602425b298c6388249f1efc85412ba0c Mon Sep 17 00:00:00 2001 From: Carter McBride <18412686+carterworks@users.noreply.github.com> Date: Fri, 26 Jun 2026 16:35:06 -0600 Subject: [PATCH 12/12] test(functional): restore migrated functional specs as review signal Keep the original testcafe functional specs alongside the new Vitest+Playwright+MSW integration suite until these migration branches merge, so reviewers retain the pre-migration signal. --- .../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 +++++++++++++++++++ 4 files changed, 192 insertions(+) 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 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(); +});