From 5cd650cd9fdf3137cb0405f13d67cfe9227518b5 Mon Sep 17 00:00:00 2001 From: Jang ho Jung Date: Mon, 27 Jan 2025 19:55:53 -0800 Subject: [PATCH 01/17] some updates --- e2e/scripts/pageHelpers.js | 22 ++++++++++++++++++- e2e/tests/desktop/registered-shopper.spec.js | 2 +- e2e/tests/dnt.spec.js | 4 +++- e2e/tests/homepage.spec.js | 2 ++ packages/commerce-sdk-react/src/auth/index.ts | 3 +++ 5 files changed, 30 insertions(+), 3 deletions(-) diff --git a/e2e/scripts/pageHelpers.js b/e2e/scripts/pageHelpers.js index b67b4a6e6c..2f236f1b9c 100644 --- a/e2e/scripts/pageHelpers.js +++ b/e2e/scripts/pageHelpers.js @@ -2,6 +2,17 @@ const { expect } = require("@playwright/test"); const config = require("../config"); const { getCreditCardExpiry } = require("../scripts/utils.js") +export const answerConsentTrackingForm = async (page, dnt = true) => { + if (await page.locator('text=Tracking Consent').count() > 0) { + var text = 'Accept' + if (dnt) + text = 'Decline' + const answerButton = page.locator('button:visible', { hasText: text }); + await expect(answerButton).toBeVisible(); + await answerButton.click(); + } +} + /** * Navigates to the `Cotton Turtleneck Sweater` PDP (Product Detail Page) on mobile * with the black variant selected @@ -11,6 +22,7 @@ const { getCreditCardExpiry } = require("../scripts/utils.js") export const navigateToPDPMobile = async ({page}) => { // Home page await page.goto(config.RETAIL_APP_HOME); + await answerConsentTrackingForm(page) await page.getByLabel("Menu", { exact: true }).click(); @@ -64,6 +76,7 @@ export const navigateToPDPMobile = async ({page}) => { */ export const navigateToPDPDesktop = async ({page}) => { await page.goto(config.RETAIL_APP_HOME); + await answerConsentTrackingForm(page) await page.getByRole("link", { name: "Womens" }).hover(); const topsNav = await page.getByRole("link", { name: "Tops", exact: true }); @@ -144,6 +157,7 @@ export const addProductToCart = async ({page, isMobile = false}) => { export const registerShopper = async ({page, userCredentials, isMobile = false}) => { // Create Account and Sign In await page.goto(config.RETAIL_APP_HOME + "/registration"); + await answerConsentTrackingForm(page) await page.waitForLoadState(); @@ -186,6 +200,8 @@ export const registerShopper = async ({page, userCredentials, isMobile = false}) */ export const validateOrderHistory = async ({page}) => { await page.goto(config.RETAIL_APP_HOME + "/account/orders"); + await answerConsentTrackingForm(page) + await expect( page.getByRole("heading", { name: /Order History/i }) ).toBeVisible(); @@ -209,6 +225,7 @@ export const validateOrderHistory = async ({page}) => { */ export const validateWishlist = async ({page}) => { await page.goto(config.RETAIL_APP_HOME + "/account/wishlist"); + await answerConsentTrackingForm(page) await expect( page.getByRole("heading", { name: /Wishlist/i }) @@ -236,6 +253,9 @@ export const validateWishlist = async ({page}) => { export const loginShopper = async ({page, userCredentials}) => { try { await page.goto(config.RETAIL_APP_HOME + "/login"); + await answerConsentTrackingForm(page) + + // await answerConsentTrackingForm(page) await page.locator("input#email").fill(userCredentials.email); await page .locator("input#password") @@ -263,7 +283,7 @@ export const loginShopper = async ({page, userCredentials}) => { */ export const searchProduct = async ({page, query, isMobile = false}) => { await page.goto(config.RETAIL_APP_HOME); - + await answerConsentTrackingForm(page) // For accessibility reasons, we have two search bars // one for desktop and one for mobile depending on your device type const searchInputs = page.locator('input[aria-label="Search for products..."]'); diff --git a/e2e/tests/desktop/registered-shopper.spec.js b/e2e/tests/desktop/registered-shopper.spec.js index c1c34afa17..9905b45175 100644 --- a/e2e/tests/desktop/registered-shopper.spec.js +++ b/e2e/tests/desktop/registered-shopper.spec.js @@ -146,7 +146,7 @@ test("Registered shopper can add item to wishlist", async ({ page }) => { page, userCredentials: REGISTERED_USER_CREDENTIALS }) - + // console.log("(JEREMY) isLoggedIn: ", isLoggedIn) if(!isLoggedIn) { await registerShopper({page, userCredentials: REGISTERED_USER_CREDENTIALS}) } diff --git a/e2e/tests/dnt.spec.js b/e2e/tests/dnt.spec.js index 9565205a21..f724298087 100644 --- a/e2e/tests/dnt.spec.js +++ b/e2e/tests/dnt.spec.js @@ -51,7 +51,7 @@ const checkDntCookie = async (page, expectedValue) => { test("Shopper can use the consent tracking form", async ({ page }) => { - await page.context().clearCookies(); + // await page.context().clearCookies(); await page.goto(config.RETAIL_APP_HOME); const modalSelector = '[aria-label="Close consent tracking form"]' @@ -77,6 +77,8 @@ test("Shopper can use the consent tracking form", async ({ page }) => { await page.click('text=Womens'); // Reloading the page after setting DNT makes the form not appear again await page.reload() + checkDntCookie(page, '1') + console.log("(JEREMY) dnt cookie is 1") await expect(page.getByText(/Tracking Consent/i)).toBeHidden(); // Registering after setting DNT persists the preference diff --git a/e2e/tests/homepage.spec.js b/e2e/tests/homepage.spec.js index a8f57c06f3..fe0687f9cd 100644 --- a/e2e/tests/homepage.spec.js +++ b/e2e/tests/homepage.spec.js @@ -7,10 +7,12 @@ const { test, expect } = require("@playwright/test"); const config = require("../config"); +const {answerConsentTrackingForm} = require("../scripts/pageHelpers.js") test.describe("Retail app home page loads", () => { test.beforeEach(async ({ page }) => { await page.goto(config.RETAIL_APP_HOME); + await answerConsentTrackingForm(page); }); test("has title", async ({ page }) => { diff --git a/packages/commerce-sdk-react/src/auth/index.ts b/packages/commerce-sdk-react/src/auth/index.ts index 6dc8fed1de..76f95c771d 100644 --- a/packages/commerce-sdk-react/src/auth/index.ts +++ b/packages/commerce-sdk-react/src/auth/index.ts @@ -336,8 +336,11 @@ class Auth { if (accessToken) { const {dnt} = this.parseSlasJWT(accessToken) isInSync = dnt === dntCookieVal + console.log("(JEREMY) dnt from token: ", dnt) + console.log("(JEREMY) dnt from cookie: ", dntCookieVal) } if ((dntCookieVal !== '1' && dntCookieVal !== '0') || !isInSync) { + console.log("(JEREMY) is not in sync. deleting cookie") this.delete(DNT_COOKIE_NAME) } else { dntCookieStatus = Boolean(Number(dntCookieVal)) From b3e512037aad592d9b0d4b1f9d69eb95c7efd3af Mon Sep 17 00:00:00 2001 From: Jang ho Jung Date: Mon, 27 Jan 2025 20:01:01 -0800 Subject: [PATCH 02/17] port change just for dev --- packages/test-commerce-sdk-react/app/ssr.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/test-commerce-sdk-react/app/ssr.js b/packages/test-commerce-sdk-react/app/ssr.js index e681f6ae5a..3de25b8860 100644 --- a/packages/test-commerce-sdk-react/app/ssr.js +++ b/packages/test-commerce-sdk-react/app/ssr.js @@ -17,7 +17,7 @@ const options = { defaultCacheTimeSeconds: 600, // The port that the local dev server listens on - port: 3000, + port: 4000, // The protocol on which the development Express app listens. // Note that http://localhost is treated as a secure context for development, From 3b0726c8840f5e2e90e93a065d042fb97159e250 Mon Sep 17 00:00:00 2001 From: Jang ho Jung Date: Tue, 28 Jan 2025 00:51:23 -0800 Subject: [PATCH 03/17] DNT test suite fix --- e2e/tests/{ => desktop}/dnt.spec.js | 48 +++------- e2e/tests/mobile/dnt.spec.js | 93 +++++++++++++++++++ packages/commerce-sdk-react/src/auth/index.ts | 3 - 3 files changed, 104 insertions(+), 40 deletions(-) rename e2e/tests/{ => desktop}/dnt.spec.js (65%) create mode 100644 e2e/tests/mobile/dnt.spec.js diff --git a/e2e/tests/dnt.spec.js b/e2e/tests/desktop/dnt.spec.js similarity index 65% rename from e2e/tests/dnt.spec.js rename to e2e/tests/desktop/dnt.spec.js index f724298087..e49c2bcf0a 100644 --- a/e2e/tests/dnt.spec.js +++ b/e2e/tests/desktop/dnt.spec.js @@ -6,41 +6,16 @@ */ const { test, expect } = require("@playwright/test"); -const config = require("../config"); +const config = require("../../config.js"); const { generateUserCredentials -} = require("../scripts/utils.js"); +} = require("../../scripts/utils.js"); +const { + registerShopper +} = require("../../scripts/pageHelpers.js") const REGISTERED_USER_CREDENTIALS = generateUserCredentials(); -const registerUser = async (page) => { - await page.goto(config.RETAIL_APP_HOME + "/registration"); - - const registrationFormHeading = page.getByText(/Let's get started!/i); - await registrationFormHeading.waitFor(); - - await page - .locator("input#firstName") - .fill(REGISTERED_USER_CREDENTIALS.firstName); - await page - .locator("input#lastName") - .fill(REGISTERED_USER_CREDENTIALS.lastName); - await page.locator("input#email").fill(REGISTERED_USER_CREDENTIALS.email); - await page - .locator("input#password") - .fill(REGISTERED_USER_CREDENTIALS.password); - - await page.getByRole("button", { name: /Create Account/i }).click(); - - await expect( - page.getByRole("heading", { name: /Account Details/i }) - ).toBeVisible(); - - await expect( - page.getByRole("heading", { name: /My Account/i }) - ).toBeVisible(); -} - const checkDntCookie = async (page, expectedValue) => { var cookies = await page.context().cookies(); var cookieName = 'dw_dnt'; @@ -49,9 +24,9 @@ const checkDntCookie = async (page, expectedValue) => { expect(cookie.value).toBe(expectedValue); } +test("Shopper can use the consent tracking form", async ({page}) => { + await page.context().clearCookies(); -test("Shopper can use the consent tracking form", async ({ page }) => { - // await page.context().clearCookies(); await page.goto(config.RETAIL_APP_HOME); const modalSelector = '[aria-label="Close consent tracking form"]' @@ -62,6 +37,7 @@ test("Shopper can use the consent tracking form", async ({ page }) => { const declineButton = page.locator('button:visible', { hasText: 'Decline' }); await expect(declineButton).toBeVisible(); await declineButton.click(); + await page.waitForTimeout(5000); // Intercept einstein request let apiCallsMade = false; @@ -71,19 +47,17 @@ test("Shopper can use the consent tracking form", async ({ page }) => { }); // The value of 1 comes from defaultDnt prop in _app-config/index.jsx - checkDntCookie(page, '1') + await checkDntCookie(page, '1') // Trigger einstein events await page.click('text=Womens'); // Reloading the page after setting DNT makes the form not appear again await page.reload() - checkDntCookie(page, '1') - console.log("(JEREMY) dnt cookie is 1") await expect(page.getByText(/Tracking Consent/i)).toBeHidden(); // Registering after setting DNT persists the preference - await registerUser(page) - checkDntCookie(page, '1') + await registerShopper({page, userCredentials: REGISTERED_USER_CREDENTIALS}); + await checkDntCookie(page, '1') // Logging out clears the preference const buttons = await page.getByText(/Log Out/i).elementHandles(); diff --git a/e2e/tests/mobile/dnt.spec.js b/e2e/tests/mobile/dnt.spec.js new file mode 100644 index 0000000000..8fd9ba8269 --- /dev/null +++ b/e2e/tests/mobile/dnt.spec.js @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2023, Salesforce, Inc. + * All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause + */ + +const { test, expect } = require("@playwright/test"); +const config = require("../../config.js"); +const { + generateUserCredentials +} = require("../../scripts/utils.js"); +const { + registerShopper +} = require("../../scripts/pageHelpers.js") + +const REGISTERED_USER_CREDENTIALS = generateUserCredentials(); + +const checkDntCookie = async (page, expectedValue) => { + var cookies = await page.context().cookies(); + var cookieName = 'dw_dnt'; + var cookie = cookies.find(cookie => cookie.name === cookieName); + expect(cookie).toBeTruthy(); + expect(cookie.value).toBe(expectedValue); +} + +test("Shopper can use the consent tracking form", async ({page}) => { + await page.context().clearCookies(); + + await page.goto(config.RETAIL_APP_HOME); + + const modalSelector = '[aria-label="Close consent tracking form"]' + page.locator(modalSelector).waitFor() + await expect(page.getByText(/Tracking Consent/i)).toBeVisible({timeout: 10000}); + + // Decline Tracking + const declineButton = page.locator('button:visible', { hasText: 'Decline' }); + await expect(declineButton).toBeVisible(); + await declineButton.click(); + await page.waitForTimeout(5000); + + // Intercept einstein request + let apiCallsMade = false; + await page.route('https://api.cquotient.com/v3/activities/aaij-MobileFirst/viewCategory', (route) => { + apiCallsMade = true; + route.continue(); + }); + + // The value of 1 comes from defaultDnt prop in _app-config/index.jsx + await checkDntCookie(page, '1') + + // Trigger einstein events + await page.getByLabel("Menu", { exact: true }).click(); + + // SSR nav loads top level categories as direct links so we wait till all sub-categories load in the accordion + const categoryAccordion = page.locator( + "#category-nav .chakra-accordion__button svg+:text('Womens')" + ); + await categoryAccordion.waitFor(); + + await page.getByRole("button", { name: "Womens" }).click(); + + const clothingNav = page.getByRole("button", { name: "Clothing" }); + + await clothingNav.waitFor(); + + await clothingNav.click(); + // Reloading the page after setting DNT makes the form not appear again + await page.reload() + await expect(page.getByText(/Tracking Consent/i)).toBeHidden(); + + // Registering after setting DNT persists the preference + await registerShopper({page, userCredentials: REGISTERED_USER_CREDENTIALS}); + await checkDntCookie(page, '1') + + // Logging out clears the preference + await page.getByRole("heading", { name: /My Account/i }).click() + const buttons = await page.getByText(/Log Out/i).elementHandles(); + for (const button of buttons) { + if (await button.isVisible()) { + await button.click(); + break; + } + } + + var cookies = await page.context().cookies(); + if (cookies.some(item => item.name === "dw_dnt")) { + throw new Error('dw_dnt still exists in the cookies'); + } + await page.reload(); + await expect(page.getByText(/Tracking Consent/i)).toBeVisible({timeout: 10000}); + expect(apiCallsMade).toBe(false); +}); diff --git a/packages/commerce-sdk-react/src/auth/index.ts b/packages/commerce-sdk-react/src/auth/index.ts index 76f95c771d..6dc8fed1de 100644 --- a/packages/commerce-sdk-react/src/auth/index.ts +++ b/packages/commerce-sdk-react/src/auth/index.ts @@ -336,11 +336,8 @@ class Auth { if (accessToken) { const {dnt} = this.parseSlasJWT(accessToken) isInSync = dnt === dntCookieVal - console.log("(JEREMY) dnt from token: ", dnt) - console.log("(JEREMY) dnt from cookie: ", dntCookieVal) } if ((dntCookieVal !== '1' && dntCookieVal !== '0') || !isInSync) { - console.log("(JEREMY) is not in sync. deleting cookie") this.delete(DNT_COOKIE_NAME) } else { dntCookieStatus = Boolean(Number(dntCookieVal)) From db482741de18d6dfccf2f045b832c4864d9b72db Mon Sep 17 00:00:00 2001 From: Jang ho Jung Date: Tue, 28 Jan 2025 00:53:09 -0800 Subject: [PATCH 04/17] Put back port --- packages/template-retail-react-app/app/ssr.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/template-retail-react-app/app/ssr.js b/packages/template-retail-react-app/app/ssr.js index 566af3e496..e48fe38bdb 100644 --- a/packages/template-retail-react-app/app/ssr.js +++ b/packages/template-retail-react-app/app/ssr.js @@ -33,7 +33,7 @@ const options = { mobify: getConfig(), // The port that the local dev server listens on - port: 3000, + port: 4000, // The protocol on which the development Express app listens. // Note that http://localhost is treated as a secure context for development, From ae34972314a934553a473d9b4a79dc9b8366862e Mon Sep 17 00:00:00 2001 From: Jang ho Jung Date: Tue, 28 Jan 2025 00:54:19 -0800 Subject: [PATCH 05/17] revert port --- packages/template-retail-react-app/app/ssr.js | 2 +- packages/test-commerce-sdk-react/app/ssr.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/template-retail-react-app/app/ssr.js b/packages/template-retail-react-app/app/ssr.js index e48fe38bdb..566af3e496 100644 --- a/packages/template-retail-react-app/app/ssr.js +++ b/packages/template-retail-react-app/app/ssr.js @@ -33,7 +33,7 @@ const options = { mobify: getConfig(), // The port that the local dev server listens on - port: 4000, + port: 3000, // The protocol on which the development Express app listens. // Note that http://localhost is treated as a secure context for development, diff --git a/packages/test-commerce-sdk-react/app/ssr.js b/packages/test-commerce-sdk-react/app/ssr.js index 3de25b8860..e681f6ae5a 100644 --- a/packages/test-commerce-sdk-react/app/ssr.js +++ b/packages/test-commerce-sdk-react/app/ssr.js @@ -17,7 +17,7 @@ const options = { defaultCacheTimeSeconds: 600, // The port that the local dev server listens on - port: 4000, + port: 3000, // The protocol on which the development Express app listens. // Note that http://localhost is treated as a secure context for development, From 096e2e28f0999f24eda88bbf8033f1d7ba0daf70 Mon Sep 17 00:00:00 2001 From: Jang ho Jung Date: Tue, 28 Jan 2025 01:00:20 -0800 Subject: [PATCH 06/17] cleanup --- e2e/scripts/pageHelpers.js | 1 - e2e/tests/mobile/dnt.spec.js | 1 - 2 files changed, 2 deletions(-) diff --git a/e2e/scripts/pageHelpers.js b/e2e/scripts/pageHelpers.js index 2f236f1b9c..26f1e38075 100644 --- a/e2e/scripts/pageHelpers.js +++ b/e2e/scripts/pageHelpers.js @@ -255,7 +255,6 @@ export const loginShopper = async ({page, userCredentials}) => { await page.goto(config.RETAIL_APP_HOME + "/login"); await answerConsentTrackingForm(page) - // await answerConsentTrackingForm(page) await page.locator("input#email").fill(userCredentials.email); await page .locator("input#password") diff --git a/e2e/tests/mobile/dnt.spec.js b/e2e/tests/mobile/dnt.spec.js index 8fd9ba8269..0a37bb4652 100644 --- a/e2e/tests/mobile/dnt.spec.js +++ b/e2e/tests/mobile/dnt.spec.js @@ -37,7 +37,6 @@ test("Shopper can use the consent tracking form", async ({page}) => { const declineButton = page.locator('button:visible', { hasText: 'Decline' }); await expect(declineButton).toBeVisible(); await declineButton.click(); - await page.waitForTimeout(5000); // Intercept einstein request let apiCallsMade = false; From 381add643e80b8b2a751454c8bcd56d881a3a719 Mon Sep 17 00:00:00 2001 From: Jang ho Jung Date: Tue, 28 Jan 2025 09:32:04 -0800 Subject: [PATCH 07/17] comments --- e2e/scripts/pageHelpers.js | 11 ++++++++++- e2e/tests/desktop/registered-shopper.spec.js | 2 +- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/e2e/scripts/pageHelpers.js b/e2e/scripts/pageHelpers.js index 26f1e38075..72eb795055 100644 --- a/e2e/scripts/pageHelpers.js +++ b/e2e/scripts/pageHelpers.js @@ -2,7 +2,16 @@ const { expect } = require("@playwright/test"); const config = require("../config"); const { getCreditCardExpiry } = require("../scripts/utils.js") -export const answerConsentTrackingForm = async (page, dnt = true) => { +/** + * Give an answer to the consent tracking form. + * + * Note: the consent tracking form hovers over some elements in the app. This can cause a test to fail. + * Run this function after a page.goto to release the form from view. + * + * @param {Object} page - Object that represents a tab/window in the browser provided by playwright + * @param {Boolean} dnt - Do Not Track value to answer the form. False to enable tracking, True to disable tracking. + */ +export const answerConsentTrackingForm = async (page, dnt = false) => { if (await page.locator('text=Tracking Consent').count() > 0) { var text = 'Accept' if (dnt) diff --git a/e2e/tests/desktop/registered-shopper.spec.js b/e2e/tests/desktop/registered-shopper.spec.js index 9905b45175..c1c34afa17 100644 --- a/e2e/tests/desktop/registered-shopper.spec.js +++ b/e2e/tests/desktop/registered-shopper.spec.js @@ -146,7 +146,7 @@ test("Registered shopper can add item to wishlist", async ({ page }) => { page, userCredentials: REGISTERED_USER_CREDENTIALS }) - // console.log("(JEREMY) isLoggedIn: ", isLoggedIn) + if(!isLoggedIn) { await registerShopper({page, userCredentials: REGISTERED_USER_CREDENTIALS}) } From e810f5871eacb23128aa798784788f4ad825b56d Mon Sep 17 00:00:00 2001 From: Jang ho Jung Date: Tue, 28 Jan 2025 09:43:15 -0800 Subject: [PATCH 08/17] clean up --- e2e/tests/desktop/dnt.spec.js | 5 ++--- e2e/tests/mobile/dnt.spec.js | 3 +-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/e2e/tests/desktop/dnt.spec.js b/e2e/tests/desktop/dnt.spec.js index e49c2bcf0a..538b0115c6 100644 --- a/e2e/tests/desktop/dnt.spec.js +++ b/e2e/tests/desktop/dnt.spec.js @@ -24,7 +24,7 @@ const checkDntCookie = async (page, expectedValue) => { expect(cookie.value).toBe(expectedValue); } -test("Shopper can use the consent tracking form", async ({page}) => { +test("Shopper can use the consent tracking form", async ({ page }) => { await page.context().clearCookies(); await page.goto(config.RETAIL_APP_HOME); @@ -45,8 +45,7 @@ test("Shopper can use the consent tracking form", async ({page}) => { apiCallsMade = true; route.continue(); }); - - // The value of 1 comes from defaultDnt prop in _app-config/index.jsx + await checkDntCookie(page, '1') // Trigger einstein events diff --git a/e2e/tests/mobile/dnt.spec.js b/e2e/tests/mobile/dnt.spec.js index 0a37bb4652..66f72e7748 100644 --- a/e2e/tests/mobile/dnt.spec.js +++ b/e2e/tests/mobile/dnt.spec.js @@ -24,7 +24,7 @@ const checkDntCookie = async (page, expectedValue) => { expect(cookie.value).toBe(expectedValue); } -test("Shopper can use the consent tracking form", async ({page}) => { +test("Shopper can use the consent tracking form", async ({ page }) => { await page.context().clearCookies(); await page.goto(config.RETAIL_APP_HOME); @@ -45,7 +45,6 @@ test("Shopper can use the consent tracking form", async ({page}) => { route.continue(); }); - // The value of 1 comes from defaultDnt prop in _app-config/index.jsx await checkDntCookie(page, '1') // Trigger einstein events From 4f7b9d870bcc50135e55ae3e2020920bf13f4472 Mon Sep 17 00:00:00 2001 From: Jang ho Jung Date: Tue, 28 Jan 2025 11:30:39 -0800 Subject: [PATCH 09/17] some logging for dev --- .../template-retail-react-app/app/pages/product-list/index.jsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/template-retail-react-app/app/pages/product-list/index.jsx b/packages/template-retail-react-app/app/pages/product-list/index.jsx index d96422c7c7..3ba2c95c0f 100644 --- a/packages/template-retail-react-app/app/pages/product-list/index.jsx +++ b/packages/template-retail-react-app/app/pages/product-list/index.jsx @@ -105,6 +105,7 @@ const REFINEMENT_DISALLOW_LIST = ['c_isNew'] * allowable filters and sort refinements. */ const ProductList = (props) => { + console.log("(JEREMY) in ProductList") // Using destructuring to omit properties; we must rename `isLoading` because we use a different // `isLoading` later in this function. // eslint-disable-next-line react/prop-types, @typescript-eslint/no-unused-vars @@ -399,6 +400,8 @@ const ProductList = (props) => { } }, [productSearchResult]) + console.log("(JEREMY) productSearchResult: ", productSearchResult) + return ( Date: Tue, 28 Jan 2025 12:21:30 -0800 Subject: [PATCH 10/17] Revert "some logging for dev" This reverts commit 4f7b9d870bcc50135e55ae3e2020920bf13f4472. --- .../template-retail-react-app/app/pages/product-list/index.jsx | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/template-retail-react-app/app/pages/product-list/index.jsx b/packages/template-retail-react-app/app/pages/product-list/index.jsx index 3ba2c95c0f..d96422c7c7 100644 --- a/packages/template-retail-react-app/app/pages/product-list/index.jsx +++ b/packages/template-retail-react-app/app/pages/product-list/index.jsx @@ -105,7 +105,6 @@ const REFINEMENT_DISALLOW_LIST = ['c_isNew'] * allowable filters and sort refinements. */ const ProductList = (props) => { - console.log("(JEREMY) in ProductList") // Using destructuring to omit properties; we must rename `isLoading` because we use a different // `isLoading` later in this function. // eslint-disable-next-line react/prop-types, @typescript-eslint/no-unused-vars @@ -400,8 +399,6 @@ const ProductList = (props) => { } }, [productSearchResult]) - console.log("(JEREMY) productSearchResult: ", productSearchResult) - return ( Date: Tue, 28 Jan 2025 16:11:02 -0800 Subject: [PATCH 11/17] Fix wishlist tests --- e2e/config.js | 2 +- e2e/scripts/pageHelpers.js | 17 +++++++--------- e2e/tests/desktop/registered-shopper.spec.js | 2 +- e2e/tests/mobile/registered-shopper.spec.js | 2 +- .../config/default.js | 20 +++++++++---------- 5 files changed, 20 insertions(+), 23 deletions(-) diff --git a/e2e/config.js b/e2e/config.js index 363012cf3a..9a9b82d8b3 100644 --- a/e2e/config.js +++ b/e2e/config.js @@ -7,7 +7,7 @@ module.exports = { RETAIL_APP_HOME: - process.env.RETAIL_APP_HOME || + process.env.RETAIL_APP_HOME || "localhost:3000" || "https://scaffold-pwa-e2e-tests-pwa-kit.mobify-storefront.com", GENERATED_PROJECTS_DIR: "../generated-projects", GENERATE_PROJECTS: ["retail-app-demo", "retail-app-ext", "retail-app-no-ext"], diff --git a/e2e/scripts/pageHelpers.js b/e2e/scripts/pageHelpers.js index 72eb795055..8bb76d389b 100644 --- a/e2e/scripts/pageHelpers.js +++ b/e2e/scripts/pageHelpers.js @@ -184,9 +184,10 @@ export const registerShopper = async ({page, userCredentials, isMobile = false}) .locator("input#password") .fill(userCredentials.password); + const tokenResponsePromise=page.waitForResponse('**/shopper/auth/v1/organizations/**/oauth2/token') await page.getByRole("button", { name: /Create Account/i }).click(); - - await page.waitForLoadState(); + await tokenResponsePromise; + expect((await tokenResponsePromise).status()).toBe(200); await expect( page.getByRole("heading", { name: /Account Details/i }) @@ -268,15 +269,11 @@ export const loginShopper = async ({page, userCredentials}) => { await page .locator("input#password") .fill(userCredentials.password); + + const tokenResponsePromise=page.waitForResponse('**/shopper/auth/v1/organizations/**/oauth2/token') await page.getByRole("button", { name: /Sign In/i }).click(); - - await page.waitForLoadState(); - - // redirected to Account Details page after logging in - await expect( - page.getByRole("heading", { name: /Account Details/i }) - ).toBeVisible({ timeout: 2000 }); - return true; + await tokenResponsePromise; + return await tokenResponsePromise.status() === 200; } catch { return false; } diff --git a/e2e/tests/desktop/registered-shopper.spec.js b/e2e/tests/desktop/registered-shopper.spec.js index c1c34afa17..a0433aebce 100644 --- a/e2e/tests/desktop/registered-shopper.spec.js +++ b/e2e/tests/desktop/registered-shopper.spec.js @@ -148,7 +148,7 @@ test("Registered shopper can add item to wishlist", async ({ page }) => { }) if(!isLoggedIn) { - await registerShopper({page, userCredentials: REGISTERED_USER_CREDENTIALS}) + await registerShopper({page, userCredentials: generateUserCredentials()}) } // Navigate to PDP diff --git a/e2e/tests/mobile/registered-shopper.spec.js b/e2e/tests/mobile/registered-shopper.spec.js index e751a85ea7..19c134a60f 100644 --- a/e2e/tests/mobile/registered-shopper.spec.js +++ b/e2e/tests/mobile/registered-shopper.spec.js @@ -153,7 +153,7 @@ test("Registered shopper can add item to wishlist", async ({ page }) => { if(!isLoggedIn) { await registerShopper({ page, - userCredentials: REGISTERED_USER_CREDENTIALS, + userCredentials: generateUserCredentials(), isMobile: true }) } diff --git a/packages/template-retail-react-app/config/default.js b/packages/template-retail-react-app/config/default.js index 8fb5673dd2..e6d4d94a14 100644 --- a/packages/template-retail-react-app/config/default.js +++ b/packages/template-retail-react-app/config/default.js @@ -15,19 +15,19 @@ module.exports = { showDefaults: true, interpretPlusSignAsSpace: false }, - defaultSite: 'RefArchGlobal', - siteAliases: { - RefArch: 'us', - RefArchGlobal: 'global' - }, + defaultSite: 'RefArch', + // siteAliases: { + // RefArch: 'us', + // RefArchGlobal: 'global' + // }, sites, commerceAPI: { proxyPath: `/mobify/proxy/api`, parameters: { - clientId: 'c9c45bfd-0ed3-4aa2-9971-40f88962b836', - organizationId: 'f_ecom_zzrf_001', - shortCode: '8o7m175y', - siteId: 'RefArchGlobal' + clientId: '987fc116-d30c-4537-93cb-c2bd433c3b5a', + organizationId: 'f_ecom_zzrf_002', + shortCode: 'kv7kzm78', + siteId: 'RefArch' } }, einsteinAPI: { @@ -57,7 +57,7 @@ module.exports = { path: 'api' }, { - host: 'zzrf-001.dx.commercecloud.salesforce.com', + host: 'zzrf-002.dx.commercecloud.salesforce.com', path: 'ocapi' } ] From 4ccfbc946846de620fdcae94378d31bdc4759b27 Mon Sep 17 00:00:00 2001 From: Jainam Tushar Sheth Date: Tue, 28 Jan 2025 16:13:18 -0800 Subject: [PATCH 12/17] Remove localhost from config --- e2e/config.js | 2 +- e2e/tests/desktop/registered-shopper.spec.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/e2e/config.js b/e2e/config.js index 9a9b82d8b3..363012cf3a 100644 --- a/e2e/config.js +++ b/e2e/config.js @@ -7,7 +7,7 @@ module.exports = { RETAIL_APP_HOME: - process.env.RETAIL_APP_HOME || "localhost:3000" || + process.env.RETAIL_APP_HOME || "https://scaffold-pwa-e2e-tests-pwa-kit.mobify-storefront.com", GENERATED_PROJECTS_DIR: "../generated-projects", GENERATE_PROJECTS: ["retail-app-demo", "retail-app-ext", "retail-app-no-ext"], diff --git a/e2e/tests/desktop/registered-shopper.spec.js b/e2e/tests/desktop/registered-shopper.spec.js index a0433aebce..bc6aa7fada 100644 --- a/e2e/tests/desktop/registered-shopper.spec.js +++ b/e2e/tests/desktop/registered-shopper.spec.js @@ -148,7 +148,7 @@ test("Registered shopper can add item to wishlist", async ({ page }) => { }) if(!isLoggedIn) { - await registerShopper({page, userCredentials: generateUserCredentials()}) + await registerShopper({page, userCredentials: generateUserCredentials() }) } // Navigate to PDP From 65b70db6affc5627d761698fabea4e441ddfa21d Mon Sep 17 00:00:00 2001 From: Jainam Tushar Sheth Date: Wed, 29 Jan 2025 10:15:07 -0800 Subject: [PATCH 13/17] Revert PWA Kit config --- .../config/default.js | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/packages/template-retail-react-app/config/default.js b/packages/template-retail-react-app/config/default.js index e6d4d94a14..502ba42e62 100644 --- a/packages/template-retail-react-app/config/default.js +++ b/packages/template-retail-react-app/config/default.js @@ -15,19 +15,19 @@ module.exports = { showDefaults: true, interpretPlusSignAsSpace: false }, - defaultSite: 'RefArch', - // siteAliases: { - // RefArch: 'us', - // RefArchGlobal: 'global' - // }, + defaultSite: 'RefArchGlobal', + siteAliases: { + RefArch: 'us', + RefArchGlobal: 'global' + }, sites, commerceAPI: { proxyPath: `/mobify/proxy/api`, parameters: { - clientId: '987fc116-d30c-4537-93cb-c2bd433c3b5a', - organizationId: 'f_ecom_zzrf_002', - shortCode: 'kv7kzm78', - siteId: 'RefArch' + clientId: 'c9c45bfd-0ed3-4aa2-9971-40f88962b836', + organizationId: 'f_ecom_zzrf_001', + shortCode: '8o7m175y', + siteId: 'RefArchGlobal' } }, einsteinAPI: { @@ -53,11 +53,11 @@ module.exports = { ssrFunctionNodeVersion: '20.x', proxyConfigs: [ { - host: 'kv7kzm78.api.commercecloud.salesforce.com', + host: '8o7m175y.api.commercecloud.salesforce.com', path: 'api' }, { - host: 'zzrf-002.dx.commercecloud.salesforce.com', + host: 'zzrf-001.dx.commercecloud.salesforce.com', path: 'ocapi' } ] From 736303febf65652ec8193000a1b386cb804c2f10 Mon Sep 17 00:00:00 2001 From: Jang ho Jung Date: Wed, 29 Jan 2025 10:44:42 -0800 Subject: [PATCH 14/17] try different shortcode --- packages/template-retail-react-app/config/default.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/template-retail-react-app/config/default.js b/packages/template-retail-react-app/config/default.js index 502ba42e62..1677fe5929 100644 --- a/packages/template-retail-react-app/config/default.js +++ b/packages/template-retail-react-app/config/default.js @@ -26,7 +26,7 @@ module.exports = { parameters: { clientId: 'c9c45bfd-0ed3-4aa2-9971-40f88962b836', organizationId: 'f_ecom_zzrf_001', - shortCode: '8o7m175y', + shortCode: 'kv7kzm78', siteId: 'RefArchGlobal' } }, @@ -53,7 +53,7 @@ module.exports = { ssrFunctionNodeVersion: '20.x', proxyConfigs: [ { - host: '8o7m175y.api.commercecloud.salesforce.com', + host: 'kv7kzm78.api.commercecloud.salesforce.com', path: 'api' }, { From 359d1d3fcdb5fc868d7ded4761bb20603452fbad Mon Sep 17 00:00:00 2001 From: Jang ho Jung Date: Thu, 30 Jan 2025 09:54:19 -0800 Subject: [PATCH 15/17] Revert "try different shortcode" This reverts commit 736303febf65652ec8193000a1b386cb804c2f10. --- packages/template-retail-react-app/config/default.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/template-retail-react-app/config/default.js b/packages/template-retail-react-app/config/default.js index 1677fe5929..502ba42e62 100644 --- a/packages/template-retail-react-app/config/default.js +++ b/packages/template-retail-react-app/config/default.js @@ -26,7 +26,7 @@ module.exports = { parameters: { clientId: 'c9c45bfd-0ed3-4aa2-9971-40f88962b836', organizationId: 'f_ecom_zzrf_001', - shortCode: 'kv7kzm78', + shortCode: '8o7m175y', siteId: 'RefArchGlobal' } }, @@ -53,7 +53,7 @@ module.exports = { ssrFunctionNodeVersion: '20.x', proxyConfigs: [ { - host: 'kv7kzm78.api.commercecloud.salesforce.com', + host: '8o7m175y.api.commercecloud.salesforce.com', path: 'api' }, { From 953d25f6480ba7854b5ccdfdc05ef2543411627a Mon Sep 17 00:00:00 2001 From: Jang ho Jung Date: Thu, 30 Jan 2025 09:54:48 -0800 Subject: [PATCH 16/17] restore shortcode in proxy config --- packages/template-retail-react-app/config/default.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/template-retail-react-app/config/default.js b/packages/template-retail-react-app/config/default.js index 502ba42e62..8fb5673dd2 100644 --- a/packages/template-retail-react-app/config/default.js +++ b/packages/template-retail-react-app/config/default.js @@ -53,7 +53,7 @@ module.exports = { ssrFunctionNodeVersion: '20.x', proxyConfigs: [ { - host: '8o7m175y.api.commercecloud.salesforce.com', + host: 'kv7kzm78.api.commercecloud.salesforce.com', path: 'api' }, { From c006b9e7f970e0981b3c9735b7dd34ac90c49206 Mon Sep 17 00:00:00 2001 From: Jang ho Jung Date: Thu, 30 Jan 2025 11:13:42 -0800 Subject: [PATCH 17/17] A comment --- e2e/scripts/pageHelpers.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/e2e/scripts/pageHelpers.js b/e2e/scripts/pageHelpers.js index 8bb76d389b..ba6e01c92b 100644 --- a/e2e/scripts/pageHelpers.js +++ b/e2e/scripts/pageHelpers.js @@ -183,7 +183,9 @@ export const registerShopper = async ({page, userCredentials, isMobile = false}) await page .locator("input#password") .fill(userCredentials.password); - + + // Best Practice: await the network call and assert on the network response rather than waiting for pageLoadState() + // to avoid race conditions from lock in pageLoadState being released before network call resolves const tokenResponsePromise=page.waitForResponse('**/shopper/auth/v1/organizations/**/oauth2/token') await page.getByRole("button", { name: /Create Account/i }).click(); await tokenResponsePromise;