diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml
index ed31c9b22d..f33c557fdc 100644
--- a/.github/workflows/e2e.yml
+++ b/.github/workflows/e2e.yml
@@ -11,18 +11,22 @@ jobs:
fail-fast: false
matrix:
# Run all matrix env at once because we will not deploy demo app to MRT.
- node: [16, 18, 20]
- npm: [8, 9, 10]
- exclude: # node 16 is not compatible with npm 10
+ node: [16, 18, 20, 22]
+ npm: [8, 9, 10, 11]
+ exclude: # node 16 with npm 10/11 and node 18 with npm 11 are not compatible
- node: 16
npm: 10
+ - node: 16
+ npm: 11
+ - node: 18
+ npm: 11
runs-on: ubuntu-latest
env:
# The "default" npm is the one that ships with a given version of node.
# For more: https://nodejs.org/en/download/releases/
# (We also use this env var for making sure a step runs once for the current node version)
# Note: For node 18, the default was npm 9 until v18.19.0, when it became npm 10
- IS_DEFAULT_NPM: ${{ (matrix.node == 16 && matrix.npm == 8) || (matrix.node == 18 && matrix.npm == 10) || (matrix.node == 20 && matrix.npm == 10) }}
+ IS_DEFAULT_NPM: ${{ (matrix.node == 16 && matrix.npm == 8) || (matrix.node == 18 && matrix.npm == 10) || (matrix.node == 20 && matrix.npm == 10) || (matrix.node == 22 && matrix.npm == 10) }}
steps:
- name: Checkout
uses: actions/checkout@v4
@@ -58,18 +62,22 @@ jobs:
# Run one matrix env at a time because we need to deploy each app to MRT and run e2e tests there
max-parallel: 1
matrix:
- node: [16, 18, 20]
- npm: [8, 9, 10]
- exclude: # node 16 is not compatible with npm 10
+ node: [16, 18, 20, 22]
+ npm: [8, 9, 10, 11]
+ exclude: # node 16 with npm 10/11 and node 18 with npm 11 are not compatible
- node: 16
npm: 10
+ - node: 16
+ npm: 11
+ - node: 18
+ npm: 11
runs-on: ubuntu-latest
env:
# The "default" npm is the one that ships with a given version of node.
# For more: https://nodejs.org/en/download/releases/
# (We also use this env var for making sure a step runs once for the current node version)
# Note: For node 18, the default was npm 9 until v18.19.0, when it became npm 10
- IS_DEFAULT_NPM: ${{ (matrix.node == 16 && matrix.npm == 8) || (matrix.node == 18 && matrix.npm == 10) || (matrix.node == 20 && matrix.npm == 10) }}
+ IS_DEFAULT_NPM: ${{ (matrix.node == 16 && matrix.npm == 8) || (matrix.node == 18 && matrix.npm == 10) || (matrix.node == 20 && matrix.npm == 10) || (matrix.node == 22 && matrix.npm == 10) }}
steps:
- name: Checkout
uses: actions/checkout@v4
@@ -155,18 +163,22 @@ jobs:
# Run one matrix env at a time because we need to deploy each app to MRT and run e2e tests there
max-parallel: 1
matrix:
- node: [16, 18, 20]
- npm: [8, 9, 10]
- exclude: # node 16 is not compatible with npm 10
+ node: [16, 18, 20, 22]
+ npm: [8, 9, 10, 11]
+ exclude: # node 16 with npm 10/11 and node 18 with npm 11 are not compatible
- node: 16
npm: 10
+ - node: 16
+ npm: 11
+ - node: 18
+ npm: 11
runs-on: ubuntu-latest
env:
# The "default" npm is the one that ships with a given version of node.
# For more: https://nodejs.org/en/download/releases/
# (We also use this env var for making sure a step runs once for the current node version)
# Note: For node 18, the default was npm 9 until v18.19.0, when it became npm 10
- IS_DEFAULT_NPM: ${{ (matrix.node == 16 && matrix.npm == 8) || (matrix.node == 18 && matrix.npm == 10) || (matrix.node == 20 && matrix.npm == 10) }}
+ IS_DEFAULT_NPM: ${{ (matrix.node == 16 && matrix.npm == 8) || (matrix.node == 18 && matrix.npm == 10) || (matrix.node == 20 && matrix.npm == 10) || (matrix.node == 22 && matrix.npm == 10) }}
steps:
- name: Checkout
uses: actions/checkout@v4
@@ -251,18 +263,22 @@ jobs:
max-parallel: 1
matrix:
# Run all matrix env at once because we will not deploy demo app to MRT.
- node: [16, 18, 20]
- npm: [8, 9, 10]
- exclude: # node 16 is not compatible with npm 10
+ node: [16, 18, 20, 22]
+ npm: [8, 9, 10, 11]
+ exclude: # node 16 with npm 10/11 and node 18 with npm 11 are not compatible
- node: 16
npm: 10
+ - node: 16
+ npm: 11
+ - node: 18
+ npm: 11
runs-on: ubuntu-latest
env:
# The "default" npm is the one that ships with a given version of node.
# For more: https://nodejs.org/en/download/releases/
# (We also use this env var for making sure a step runs once for the current node version)
# Note: For node 18, the default was npm 9 until v18.19.0, when it became npm 10
- IS_DEFAULT_NPM: ${{ (matrix.node == 16 && matrix.npm == 8) || (matrix.node == 18 && matrix.npm == 10) || (matrix.node == 20 && matrix.npm == 10) }}
+ IS_DEFAULT_NPM: ${{ (matrix.node == 16 && matrix.npm == 8) || (matrix.node == 18 && matrix.npm == 10) || (matrix.node == 20 && matrix.npm == 10) || (matrix.node == 22 && matrix.npm == 10) }}
steps:
- name: Checkout
uses: actions/checkout@v4
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index a0424345d3..568e6ad3f3 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -44,21 +44,24 @@ jobs:
strategy:
fail-fast: false
matrix:
- node: [16, 18, 20]
- npm: [8, 9, 10]
- exclude: # node 16 is not compatible with npm 10
+ node: [16, 18, 20, 22]
+ npm: [8, 9, 10, 11]
+ exclude: # node 16 with npm 10/11 and node 18 with npm 11 are not compatible
- node: 16
npm: 10
+ - node: 16
+ npm: 11
+ - node: 18
+ npm: 11
runs-on: ubuntu-latest
env:
# The "default" npm is the one that ships with a given version of node.
# For more: https://nodejs.org/en/download/releases/
# (We also use this env var for making sure a step runs once for the current node version)
- # Note: For node 18, the default was npm 9 until v18.19.0, when it became npm 10
- IS_DEFAULT_NPM: ${{ (matrix.node == 16 && matrix.npm == 8) || (matrix.node == 18 && matrix.npm == 10) || (matrix.node == 20 && matrix.npm == 10) }}
+ IS_DEFAULT_NPM: ${{ (matrix.node == 16 && matrix.npm == 8) || (matrix.node == 18 && matrix.npm == 10) || (matrix.node == 20 && matrix.npm == 10) || (matrix.node == 22 && matrix.npm == 10) }}
# The current recommended version for Managed Runtime:
# https://developer.salesforce.com/docs/commerce/pwa-kit-managed-runtime/guide/upgrade-node-version.html
- IS_MRT_NODE: ${{ matrix.node == 20 && matrix.npm == 10 }}
+ IS_MRT_NODE: ${{ matrix.node == 22 && matrix.npm == 10 }}
steps:
- name: Checkout
uses: actions/checkout@v3
@@ -141,21 +144,25 @@ jobs:
strategy:
fail-fast: false
matrix:
- node: [16, 18, 20]
- npm: [8, 9, 10]
- exclude: # node 16 is not compatible with npm 10
+ node: [16, 18, 20, 22]
+ npm: [8, 9, 10, 11]
+ exclude: # node 16 with npm 10/11 and node 18 with npm 11 are not compatible
- node: 16
npm: 10
+ - node: 16
+ npm: 11
+ - node: 18
+ npm: 11
runs-on: windows-latest
env:
# The "default" npm is the one that ships with a given version of node.
# For more: https://nodejs.org/en/download/releases/
# (We also use this env var for making sure a step runs once for the current node version)
# Note: For node 18, the default was npm 9 until v18.19.0, when it became npm 10
- IS_DEFAULT_NPM: ${{ (matrix.node == 16 && matrix.npm == 8) || (matrix.node == 18 && matrix.npm == 10) || (matrix.node == 20 && matrix.npm == 10) }}
+ IS_DEFAULT_NPM: ${{ (matrix.node == 16 && matrix.npm == 8) || (matrix.node == 18 && matrix.npm == 10) || (matrix.node == 20 && matrix.npm == 10) || (matrix.node == 22 && matrix.npm == 10) }}
# The current recommended version for Managed Runtime:
# https://developer.salesforce.com/docs/commerce/pwa-kit-managed-runtime/guide/upgrade-node-version.html
- IS_MRT_NODE: ${{ matrix.node == 20 && matrix.npm == 10 }}
+ IS_MRT_NODE: ${{ matrix.node == 22 && matrix.npm == 10 }}
steps:
- name: Checkout
uses: actions/checkout@v3
@@ -196,7 +203,7 @@ jobs:
- name: Setup Node
uses: actions/setup-node@v3
with:
- node-version: 20
+ node-version: 22
- name: Setup Ubuntu Machine
uses: "./.github/actions/setup_ubuntu"
@@ -295,7 +302,7 @@ jobs:
- name: Setup Node
uses: actions/setup-node@v3
with:
- node-version: 20
+ node-version: 22
- name: Setup Windows Machine
uses: "./.github/actions/setup_windows"
@@ -339,7 +346,7 @@ jobs:
strategy:
fail-fast: false
matrix:
- node: [20] # Should match node version supported by MRT.
+ node: [22] # Should match node version supported by MRT.
runs-on: ubuntu-latest
steps:
- name: Checkout
diff --git a/e2e/scripts/pageHelpers.js b/e2e/scripts/pageHelpers.js
index ee986d0f77..31a0200809 100644
--- a/e2e/scripts/pageHelpers.js
+++ b/e2e/scripts/pageHelpers.js
@@ -2,6 +2,26 @@ const { expect } = require("@playwright/test");
const config = require("../config");
const { getCreditCardExpiry } = require("../scripts/utils.js")
+/**
+ * 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)
+ 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 +31,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 +85,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 });
@@ -172,6 +194,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();
@@ -188,10 +211,13 @@ 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 page.waitForLoadState();
+ await tokenResponsePromise;
+ expect((await tokenResponsePromise).status()).toBe(200);
await expect(
page.getByRole("heading", { name: /Account Details/i })
@@ -214,6 +240,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();
@@ -237,6 +265,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 })
@@ -264,19 +293,17 @@ export const validateWishlist = async ({page}) => {
export const loginShopper = async ({page, userCredentials}) => {
try {
await page.goto(config.RETAIL_APP_HOME + "/login");
+ await answerConsentTrackingForm(page)
+
await page.locator("input#email").fill(userCredentials.email);
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;
}
@@ -328,7 +355,7 @@ export const socialLoginShopper = async ({page}) => {
*/
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/dnt.spec.js b/e2e/tests/desktop/dnt.spec.js
similarity index 67%
rename from e2e/tests/dnt.spec.js
rename to e2e/tests/desktop/dnt.spec.js
index 9565205a21..538b0115c6 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();
+
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;
@@ -69,9 +45,8 @@ 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
- checkDntCookie(page, '1')
+
+ await checkDntCookie(page, '1')
// Trigger einstein events
await page.click('text=Womens');
@@ -80,8 +55,8 @@ test("Shopper can use the consent tracking form", async ({ page }) => {
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/desktop/registered-shopper.spec.js b/e2e/tests/desktop/registered-shopper.spec.js
index 5bb39864db..f6b7ae834f 100644
--- a/e2e/tests/desktop/registered-shopper.spec.js
+++ b/e2e/tests/desktop/registered-shopper.spec.js
@@ -150,7 +150,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/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/e2e/tests/mobile/dnt.spec.js b/e2e/tests/mobile/dnt.spec.js
new file mode 100644
index 0000000000..66f72e7748
--- /dev/null
+++ b/e2e/tests/mobile/dnt.spec.js
@@ -0,0 +1,91 @@
+/*
+ * 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();
+
+ // Intercept einstein request
+ let apiCallsMade = false;
+ await page.route('https://api.cquotient.com/v3/activities/aaij-MobileFirst/viewCategory', (route) => {
+ apiCallsMade = true;
+ route.continue();
+ });
+
+ 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/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/package-lock.json b/package-lock.json
index 4a3c2a6109..a3a7b097f0 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -23,8 +23,8 @@
"syncpack": "^10.1.0"
},
"engines": {
- "node": "^16.11.0 || ^18.0.0 || ^20.0.0",
- "npm": "^8.0.0 || ^9.0.0 || ^10.0.0"
+ "node": "^16.11.0 || ^18.0.0 || ^20.0.0 || ^22.0.0",
+ "npm": "^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0"
}
},
"node_modules/@babel/code-frame": {
diff --git a/package.json b/package.json
index 27b5eb4be3..5b7213f8a6 100644
--- a/package.json
+++ b/package.json
@@ -32,8 +32,8 @@
"syncpack": "^10.1.0"
},
"engines": {
- "node": "^16.11.0 || ^18.0.0 || ^20.0.0",
- "npm": "^8.0.0 || ^9.0.0 || ^10.0.0"
+ "node": "^16.11.0 || ^18.0.0 || ^20.0.0 || ^22.0.0",
+ "npm": "^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0"
},
"dependencies": {
"node-fetch": "^2.6.9"
diff --git a/packages/commerce-sdk-react/CHANGELOG.md b/packages/commerce-sdk-react/CHANGELOG.md
index e510bd32f8..042ffc0356 100644
--- a/packages/commerce-sdk-react/CHANGELOG.md
+++ b/packages/commerce-sdk-react/CHANGELOG.md
@@ -6,6 +6,7 @@
- Update CacheUpdateMatrix for mergeBasket mutation [#2138](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/2092)
- Clear auth state if session has been invalidated by a password change [#2092](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/2092)
- DNT interface improvement [#2203](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/2203)
+- Support Node 22 [#2218](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/2218)
## v3.1.0 (Oct 28, 2024)
diff --git a/packages/commerce-sdk-react/package-lock.json b/packages/commerce-sdk-react/package-lock.json
index 87f68f39ae..85abe50081 100644
--- a/packages/commerce-sdk-react/package-lock.json
+++ b/packages/commerce-sdk-react/package-lock.json
@@ -42,8 +42,8 @@
"typescript": "4.9.5"
},
"engines": {
- "node": "^16.11.0 || ^18.0.0 || ^20.0.0",
- "npm": "^8.0.0 || ^9.0.0 || ^10.0.0"
+ "node": "^16.11.0 || ^18.0.0 || ^20.0.0 || ^22.0.0",
+ "npm": "^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0"
},
"optionalDependencies": {
"prop-types": "^15.8.1"
diff --git a/packages/commerce-sdk-react/package.json b/packages/commerce-sdk-react/package.json
index 670b7c9bb6..0da559b631 100644
--- a/packages/commerce-sdk-react/package.json
+++ b/packages/commerce-sdk-react/package.json
@@ -84,8 +84,8 @@
"react-router-dom": "^5.3.4"
},
"engines": {
- "node": "^16.11.0 || ^18.0.0 || ^20.0.0",
- "npm": "^8.0.0 || ^9.0.0 || ^10.0.0"
+ "node": "^16.11.0 || ^18.0.0 || ^20.0.0 || ^22.0.0",
+ "npm": "^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0"
},
"publishConfig": {
"directory": "dist"
diff --git a/packages/internal-lib-build/configs/babel.config.js b/packages/internal-lib-build/configs/babel.config.js
index b3d0c99dc9..113d180a04 100644
--- a/packages/internal-lib-build/configs/babel.config.js
+++ b/packages/internal-lib-build/configs/babel.config.js
@@ -10,7 +10,7 @@ const config = {
require('@babel/preset-env'),
{
targets: {
- node: 18
+ node: 22
}
}
],
diff --git a/packages/internal-lib-build/package-lock.json b/packages/internal-lib-build/package-lock.json
index 76e1cd43b8..2a08c6e0c1 100644
--- a/packages/internal-lib-build/package-lock.json
+++ b/packages/internal-lib-build/package-lock.json
@@ -50,8 +50,8 @@
"typescript": "4.9.5"
},
"engines": {
- "node": "^16.11.0 || ^18.0.0 || ^20.0.0",
- "npm": "^8.0.0 || ^9.0.0 || ^10.0.0"
+ "node": "^16.11.0 || ^18.0.0 || ^20.0.0 || ^22.0.0",
+ "npm": "^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0"
},
"peerDependencies": {
"typescript": "4.9.5"
diff --git a/packages/internal-lib-build/package.json b/packages/internal-lib-build/package.json
index 2af7e4f35c..66f26c33df 100644
--- a/packages/internal-lib-build/package.json
+++ b/packages/internal-lib-build/package.json
@@ -73,7 +73,7 @@
}
},
"engines": {
- "node": "^16.11.0 || ^18.0.0 || ^20.0.0",
- "npm": "^8.0.0 || ^9.0.0 || ^10.0.0"
+ "node": "^16.11.0 || ^18.0.0 || ^20.0.0 || ^22.0.0",
+ "npm": "^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0"
}
}
diff --git a/packages/pwa-kit-create-app/CHANGELOG.md b/packages/pwa-kit-create-app/CHANGELOG.md
index b5e9ba0152..baedec7a47 100644
--- a/packages/pwa-kit-create-app/CHANGELOG.md
+++ b/packages/pwa-kit-create-app/CHANGELOG.md
@@ -1,4 +1,5 @@
## v3.9.0-dev (Oct 29, 2024)
+- Support Node 22 [#2218](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/2218)
## v3.8.0 (Oct 28, 2024)
diff --git a/packages/pwa-kit-create-app/assets/bootstrap/js/config/default.js.hbs b/packages/pwa-kit-create-app/assets/bootstrap/js/config/default.js.hbs
index 2d2ed1bb25..74d2eaf3bb 100644
--- a/packages/pwa-kit-create-app/assets/bootstrap/js/config/default.js.hbs
+++ b/packages/pwa-kit-create-app/assets/bootstrap/js/config/default.js.hbs
@@ -66,7 +66,7 @@ module.exports = {
],
// Additional parameters that configure Express app behavior.
ssrParameters: {
- ssrFunctionNodeVersion: '20.x',
+ ssrFunctionNodeVersion: '22.x',
proxyConfigs: [
{
host: '{{answers.project.commerce.shortCode}}.api.commercecloud.salesforce.com',
diff --git a/packages/pwa-kit-create-app/assets/bootstrap/js/package.json.hbs b/packages/pwa-kit-create-app/assets/bootstrap/js/package.json.hbs
index 016ac33bb4..796d3b65a8 100644
--- a/packages/pwa-kit-create-app/assets/bootstrap/js/package.json.hbs
+++ b/packages/pwa-kit-create-app/assets/bootstrap/js/package.json.hbs
@@ -3,8 +3,8 @@
"version": "0.0.1",
"license": "See license in LICENSE",
"engines": {
- "node": "^18.0.0 || ^20.0.0",
- "npm": "^9.0.0 || ^10.0.0"
+ "node": "^18.0.0 || ^20.0.0 || ^22.0.0",
+ "npm": "^9.0.0 || ^10.0.0 || ^11.0.0"
},
"ccExtensibility": {
"extends": "{{preset.templateSource.id}}",
diff --git a/packages/pwa-kit-create-app/assets/templates/@salesforce/retail-react-app/config/default.js.hbs b/packages/pwa-kit-create-app/assets/templates/@salesforce/retail-react-app/config/default.js.hbs
index 0eaa79e0d8..59c7fd9f91 100644
--- a/packages/pwa-kit-create-app/assets/templates/@salesforce/retail-react-app/config/default.js.hbs
+++ b/packages/pwa-kit-create-app/assets/templates/@salesforce/retail-react-app/config/default.js.hbs
@@ -84,7 +84,7 @@ module.exports = {
],
// Additional parameters that configure Express app behavior.
ssrParameters: {
- ssrFunctionNodeVersion: '20.x',
+ ssrFunctionNodeVersion: '22.x',
proxyConfigs: [
{
host: '{{answers.project.commerce.shortCode}}.api.commercecloud.salesforce.com',
diff --git a/packages/pwa-kit-create-app/package-lock.json b/packages/pwa-kit-create-app/package-lock.json
index cba5041081..1197d8146c 100644
--- a/packages/pwa-kit-create-app/package-lock.json
+++ b/packages/pwa-kit-create-app/package-lock.json
@@ -25,8 +25,8 @@
"verdaccio": "^5.22.1"
},
"engines": {
- "node": "^16.11.0 || ^18.0.0 || ^20.0.0",
- "npm": "^8.0.0 || ^9.0.0 || ^10.0.0"
+ "node": "^16.11.0 || ^18.0.0 || ^20.0.0 || ^22.0.0",
+ "npm": "^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0"
}
},
"node_modules/@babel/runtime": {
diff --git a/packages/pwa-kit-create-app/package.json b/packages/pwa-kit-create-app/package.json
index 738d10c2a0..7d566081b1 100644
--- a/packages/pwa-kit-create-app/package.json
+++ b/packages/pwa-kit-create-app/package.json
@@ -43,7 +43,7 @@
"verdaccio": "^5.22.1"
},
"engines": {
- "node": "^16.11.0 || ^18.0.0 || ^20.0.0",
- "npm": "^8.0.0 || ^9.0.0 || ^10.0.0"
+ "node": "^16.11.0 || ^18.0.0 || ^20.0.0 || ^22.0.0",
+ "npm": "^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0"
}
}
diff --git a/packages/pwa-kit-dev/CHANGELOG.md b/packages/pwa-kit-dev/CHANGELOG.md
index 1503e9c384..71ba4a7766 100644
--- a/packages/pwa-kit-dev/CHANGELOG.md
+++ b/packages/pwa-kit-dev/CHANGELOG.md
@@ -1,4 +1,5 @@
## v3.9.0-dev (Oct 29, 2024)
+- Support Node 22 [#2218](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/2218)
## v3.8.0 (Oct 28, 2024)
diff --git a/packages/pwa-kit-dev/package-lock.json b/packages/pwa-kit-dev/package-lock.json
index 487ca5ec03..dccfc09047 100644
--- a/packages/pwa-kit-dev/package-lock.json
+++ b/packages/pwa-kit-dev/package-lock.json
@@ -103,8 +103,8 @@
"typescript": "4.9.5"
},
"engines": {
- "node": "^16.11.0 || ^18.0.0 || ^20.0.0",
- "npm": "^8.0.0 || ^9.0.0 || ^10.0.0"
+ "node": "^16.11.0 || ^18.0.0 || ^20.0.0 || ^22.0.0",
+ "npm": "^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0"
},
"peerDependencies": {
"@loadable/component": "^5.15.3",
diff --git a/packages/pwa-kit-dev/package.json b/packages/pwa-kit-dev/package.json
index 9c78fa9cc4..215d1490a9 100644
--- a/packages/pwa-kit-dev/package.json
+++ b/packages/pwa-kit-dev/package.json
@@ -141,8 +141,8 @@
}
},
"engines": {
- "node": "^16.11.0 || ^18.0.0 || ^20.0.0",
- "npm": "^8.0.0 || ^9.0.0 || ^10.0.0"
+ "node": "^16.11.0 || ^18.0.0 || ^20.0.0 || ^22.0.0",
+ "npm": "^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0"
},
"publishConfig": {
"directory": "dist"
diff --git a/packages/pwa-kit-dev/src/configs/babel/babel-config.js b/packages/pwa-kit-dev/src/configs/babel/babel-config.js
index 3ffbc8efbf..05439dbeab 100644
--- a/packages/pwa-kit-dev/src/configs/babel/babel-config.js
+++ b/packages/pwa-kit-dev/src/configs/babel/babel-config.js
@@ -11,7 +11,7 @@ const config = {
require('@babel/preset-env'),
{
targets: {
- node: 18
+ node: 22
}
}
],
diff --git a/packages/pwa-kit-dev/src/configs/webpack/test/package.json b/packages/pwa-kit-dev/src/configs/webpack/test/package.json
index fa9b8c1041..a7ca9da5b3 100644
--- a/packages/pwa-kit-dev/src/configs/webpack/test/package.json
+++ b/packages/pwa-kit-dev/src/configs/webpack/test/package.json
@@ -3,8 +3,8 @@
"version": "2.8.0-dev",
"license": "See license in LICENSE",
"engines": {
- "node": "^16.11.0 || ^18.0.0 || ^20.0.0",
- "npm": "^8.0.0 || ^9.0.0 || ^10.0.0"
+ "node": "^16.11.0 || ^18.0.0 || ^20.0.0 || ^22.0.0",
+ "npm": "^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0"
},
"ccExtensibility": {
"extends": "retail-react-app",
diff --git a/packages/pwa-kit-react-sdk/CHANGELOG.md b/packages/pwa-kit-react-sdk/CHANGELOG.md
index edd353a41d..8b0f042014 100644
--- a/packages/pwa-kit-react-sdk/CHANGELOG.md
+++ b/packages/pwa-kit-react-sdk/CHANGELOG.md
@@ -1,6 +1,7 @@
## v3.9.0-dev (Oct 29, 2024)
- Fix the performance logging util to not round duration. [#2199](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/2199)
- Add RedirectWithStatus component, allowing finer grained control of rediriects and their status code [#2173](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/2173)
+- Support Node 22 [#2218](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/2218)
## v3.8.0 (Oct 28, 2024)
- [Server Affinity] - Attach dwsid to SCAPI request headers [#2090](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/2090)
diff --git a/packages/pwa-kit-react-sdk/package-lock.json b/packages/pwa-kit-react-sdk/package-lock.json
index b772c3b140..f3632addd2 100644
--- a/packages/pwa-kit-react-sdk/package-lock.json
+++ b/packages/pwa-kit-react-sdk/package-lock.json
@@ -38,8 +38,8 @@
"supertest": "^4.0.2"
},
"engines": {
- "node": "^16.11.0 || ^18.0.0 || ^20.0.0",
- "npm": "^8.0.0 || ^9.0.0 || ^10.0.0"
+ "node": "^16.11.0 || ^18.0.0 || ^20.0.0 || ^22.0.0",
+ "npm": "^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0"
},
"peerDependencies": {
"@loadable/component": "^5.15.3",
diff --git a/packages/pwa-kit-react-sdk/package.json b/packages/pwa-kit-react-sdk/package.json
index ce0331117c..d3f8d96cfd 100644
--- a/packages/pwa-kit-react-sdk/package.json
+++ b/packages/pwa-kit-react-sdk/package.json
@@ -73,8 +73,8 @@
"react-router-dom": "^5.3.4"
},
"engines": {
- "node": "^16.11.0 || ^18.0.0 || ^20.0.0",
- "npm": "^8.0.0 || ^9.0.0 || ^10.0.0"
+ "node": "^16.11.0 || ^18.0.0 || ^20.0.0 || ^22.0.0",
+ "npm": "^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0"
},
"publishConfig": {
"directory": "dist"
diff --git a/packages/pwa-kit-react-sdk/setup-jest.js b/packages/pwa-kit-react-sdk/setup-jest.js
index 325513050b..2d94d3e2b1 100644
--- a/packages/pwa-kit-react-sdk/setup-jest.js
+++ b/packages/pwa-kit-react-sdk/setup-jest.js
@@ -25,7 +25,7 @@ jest.mock('@salesforce/pwa-kit-runtime/utils/ssr-config', () => {
'**/*.json'
],
ssrParameters: {
- ssrFunctionNodeVersion: '20.x',
+ ssrFunctionNodeVersion: '22.x',
proxyConfigs: [
{
host: 'kv7kzm78.api.commercecloud.salesforce.com',
diff --git a/packages/pwa-kit-runtime/CHANGELOG.md b/packages/pwa-kit-runtime/CHANGELOG.md
index c80ae51b7f..c1add78088 100644
--- a/packages/pwa-kit-runtime/CHANGELOG.md
+++ b/packages/pwa-kit-runtime/CHANGELOG.md
@@ -1,5 +1,6 @@
## v3.9.0-dev (Oct 29, 2024)
- Fix stale service worker file that could cause requests to still use old Content-Security-Policy [#2191](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/2191)
+- Support Node 22 [#2218](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/2218)
## v3.8.0 (Oct 28, 2024)
- Add proxy handling for trusted agent on behalf of (TAOB) requests [#2077](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/2077)
diff --git a/packages/pwa-kit-runtime/package-lock.json b/packages/pwa-kit-runtime/package-lock.json
index 345abc747e..6acf4261d1 100644
--- a/packages/pwa-kit-runtime/package-lock.json
+++ b/packages/pwa-kit-runtime/package-lock.json
@@ -35,11 +35,11 @@
"supertest": "^4.0.2"
},
"engines": {
- "node": "^16.11.0 || ^18.0.0 || ^20.0.0",
- "npm": "^8.0.0 || ^9.0.0 || ^10.0.0"
+ "node": "^16.11.0 || ^18.0.0 || ^20.0.0 || ^22.0.0",
+ "npm": "^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0"
},
"peerDependencies": {
- "@salesforce/pwa-kit-dev": "3.7.0"
+ "@salesforce/pwa-kit-dev": "3.9.0-dev"
},
"peerDependenciesMeta": {
"@salesforce/pwa-kit-dev": {
diff --git a/packages/pwa-kit-runtime/package.json b/packages/pwa-kit-runtime/package.json
index 3428731935..d4e6134bf5 100644
--- a/packages/pwa-kit-runtime/package.json
+++ b/packages/pwa-kit-runtime/package.json
@@ -66,8 +66,8 @@
}
},
"engines": {
- "node": "^16.11.0 || ^18.0.0 || ^20.0.0",
- "npm": "^8.0.0 || ^9.0.0 || ^10.0.0"
+ "node": "^16.11.0 || ^18.0.0 || ^20.0.0 || ^22.0.0",
+ "npm": "^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0"
},
"publishConfig": {
"directory": "dist"
diff --git a/packages/template-express-minimal/package.json b/packages/template-express-minimal/package.json
index faeb38f810..0e48647012 100644
--- a/packages/template-express-minimal/package.json
+++ b/packages/template-express-minimal/package.json
@@ -22,7 +22,7 @@
"mobify": {
"ssrEnabled": true,
"ssrParameters": {
- "ssrFunctionNodeVersion": "20.x"
+ "ssrFunctionNodeVersion": "22.x"
},
"ssrOnly": [
"ssr.js",
diff --git a/packages/template-mrt-reference-app/package-lock.json b/packages/template-mrt-reference-app/package-lock.json
index b35e69fa75..149e6a4d8e 100644
--- a/packages/template-mrt-reference-app/package-lock.json
+++ b/packages/template-mrt-reference-app/package-lock.json
@@ -22,8 +22,8 @@
"supertest": "^4.0.2"
},
"engines": {
- "node": "^16.11.0 || ^18.0.0 || ^20.0.0",
- "npm": "^8.0.0 || ^9.0.0 || ^10.0.0"
+ "node": "^16.11.0 || ^18.0.0 || ^20.0.0 || ^22.0.0",
+ "npm": "^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0"
}
},
"node_modules/@aws-crypto/crc32": {
diff --git a/packages/template-mrt-reference-app/package.json b/packages/template-mrt-reference-app/package.json
index 489c6f7955..f2121266c1 100644
--- a/packages/template-mrt-reference-app/package.json
+++ b/packages/template-mrt-reference-app/package.json
@@ -25,13 +25,13 @@
"supertest": "^4.0.2"
},
"engines": {
- "node": "^16.11.0 || ^18.0.0 || ^20.0.0",
- "npm": "^8.0.0 || ^9.0.0 || ^10.0.0"
+ "node": "^16.11.0 || ^18.0.0 || ^20.0.0 || ^22.0.0",
+ "npm": "^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0"
},
"mobify": {
"ssrEnabled": true,
"ssrParameters": {
- "ssrFunctionNodeVersion": "20.x",
+ "ssrFunctionNodeVersion": "22.x",
"proxyConfigs": [
{
"host": "httpbin.org",
diff --git a/packages/template-retail-react-app/CHANGELOG.md b/packages/template-retail-react-app/CHANGELOG.md
index d923697c7f..5b0c45c5e7 100644
--- a/packages/template-retail-react-app/CHANGELOG.md
+++ b/packages/template-retail-react-app/CHANGELOG.md
@@ -10,6 +10,9 @@
- [BUG] Fixed "getCheckboxProps is not a function" when rendering checkout page in generated app.[#2140](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/2140)
- Replace transfer basket call with merge basket on checkout [#2138](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/2138)
- [BUG] Fix images being fetced multiple times on Safari [#2223](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/2223)
+- Support Node 22 [#2218](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/2218)
+tags
+- PDP / PLP: Add page meta data tags that have been defined in BM [#2232](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/2232)
### Accessibility Improvements
- [a11y] Fix LinkList component to follow a11y practise [#2098])(https://github.com/SalesforceCommerceCloud/pwa-kit/pull/2098)
diff --git a/packages/template-retail-react-app/app/pages/product-detail/index.jsx b/packages/template-retail-react-app/app/pages/product-detail/index.jsx
index ea7c8be085..51533402dc 100644
--- a/packages/template-retail-react-app/app/pages/product-detail/index.jsx
+++ b/packages/template-retail-react-app/app/pages/product-detail/index.jsx
@@ -99,7 +99,8 @@ const ProductDetail = () => {
'prices',
'variations',
'set_products',
- 'bundled_products'
+ 'bundled_products',
+ 'page_meta_tags'
],
allImages: true
}
@@ -455,7 +456,15 @@ const ProductDetail = () => {
>
{product?.pageTitle}
-
+ {product?.pageMetaTags?.length > 0 &&
+ product.pageMetaTags.map(({id, value}) => (
+
+ ))}
+ {/* Fallback for description if not included in pageMetaTags */}
+ {!product?.pageMetaTags?.some((tag) => tag.id === 'description') &&
+ product?.pageDescription && (
+
+ )}
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..52640fcb96 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
@@ -159,7 +159,14 @@ const ProductList = (props) => {
perPricebook: true,
allVariationProperties: true,
allImages: true,
- expand: ['promotions', 'variations', 'prices', 'images', 'custom_properties'],
+ expand: [
+ 'promotions',
+ 'variations',
+ 'prices',
+ 'images',
+ 'page_meta_tags',
+ 'custom_properties'
+ ],
refine: _refine
}
},
@@ -411,6 +418,9 @@ const ProductList = (props) => {
{category?.pageTitle ?? searchQuery}
+ {productSearchResult?.pageMetaTags?.map(({id, value}) => {
+ return
+ })}
{showNoResults ? (
diff --git a/packages/template-retail-react-app/config/default.js b/packages/template-retail-react-app/config/default.js
index 7fbec2011e..40cbac42a9 100644
--- a/packages/template-retail-react-app/config/default.js
+++ b/packages/template-retail-react-app/config/default.js
@@ -65,7 +65,7 @@ module.exports = {
'**/*.json'
],
ssrParameters: {
- ssrFunctionNodeVersion: '20.x',
+ ssrFunctionNodeVersion: '22.x',
proxyConfigs: [
{
host: 'kv7kzm78.api.commercecloud.salesforce.com',
diff --git a/packages/template-retail-react-app/config/mocks/default.js b/packages/template-retail-react-app/config/mocks/default.js
index 5c04d542fb..c157e2449b 100644
--- a/packages/template-retail-react-app/config/mocks/default.js
+++ b/packages/template-retail-react-app/config/mocks/default.js
@@ -117,7 +117,7 @@ module.exports = {
],
// Additional parameters that configure Express app behavior.
ssrParameters: {
- ssrFunctionNodeVersion: '20.x',
+ ssrFunctionNodeVersion: '22.x',
proxyConfigs: [
{
host: 'localhost:8888',
diff --git a/packages/template-retail-react-app/package-lock.json b/packages/template-retail-react-app/package-lock.json
index 7ef4858b9e..96e3e0af3e 100644
--- a/packages/template-retail-react-app/package-lock.json
+++ b/packages/template-retail-react-app/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "@salesforce/retail-react-app",
- "version": "5.1.0-dev",
+ "version": "6.0.0-dev",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@salesforce/retail-react-app",
- "version": "5.1.0-dev",
+ "version": "6.0.0-dev",
"license": "See license in LICENSE",
"dependencies": {
"@chakra-ui/icons": "^2.0.19",
@@ -54,8 +54,8 @@
"react-router-dom": "^5.3.4"
},
"engines": {
- "node": "^16.11.0 || ^18.0.0 || ^20.0.0",
- "npm": "^8.0.0 || ^9.0.0 || ^10.0.0"
+ "node": "^16.11.0 || ^18.0.0 || ^20.0.0 || ^22.0.0",
+ "npm": "^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0"
}
},
"node_modules/@adobe/css-tools": {
diff --git a/packages/template-retail-react-app/package.json b/packages/template-retail-react-app/package.json
index 8bd6a6d02f..9214725209 100644
--- a/packages/template-retail-react-app/package.json
+++ b/packages/template-retail-react-app/package.json
@@ -87,8 +87,8 @@
"cross-env": "^5.2.1"
},
"engines": {
- "node": "^16.11.0 || ^18.0.0 || ^20.0.0",
- "npm": "^8.0.0 || ^9.0.0 || ^10.0.0"
+ "node": "^16.11.0 || ^18.0.0 || ^20.0.0 || ^22.0.0",
+ "npm": "^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0"
},
"bundlesize": [
{
diff --git a/packages/template-typescript-minimal/package-lock.json b/packages/template-typescript-minimal/package-lock.json
index 6ed08729a1..57bf8c3354 100644
--- a/packages/template-typescript-minimal/package-lock.json
+++ b/packages/template-typescript-minimal/package-lock.json
@@ -20,8 +20,8 @@
"typescript": "4.9.5"
},
"engines": {
- "node": "^16.11.0 || ^18.0.0 || ^20.0.0",
- "npm": "^8.0.0 || ^9.0.0 || ^10.0.0"
+ "node": "^16.11.0 || ^18.0.0 || ^20.0.0 || ^22.0.0",
+ "npm": "^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0"
}
},
"node_modules/@babel/runtime": {
diff --git a/packages/template-typescript-minimal/package.json b/packages/template-typescript-minimal/package.json
index 8be41feef4..d4e104180f 100644
--- a/packages/template-typescript-minimal/package.json
+++ b/packages/template-typescript-minimal/package.json
@@ -32,8 +32,8 @@
"typescript": "4.9.5"
},
"engines": {
- "node": "^16.11.0 || ^18.0.0 || ^20.0.0",
- "npm": "^8.0.0 || ^9.0.0 || ^10.0.0"
+ "node": "^16.11.0 || ^18.0.0 || ^20.0.0 || ^22.0.0",
+ "npm": "^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0"
},
"mobify": {
"ssrEnabled": true,
@@ -50,7 +50,7 @@
"**/*.json"
],
"ssrParameters": {
- "ssrFunctionNodeVersion": "20.x",
+ "ssrFunctionNodeVersion": "22.x",
"proxyConfigs": [
{
"host": "kv7kzm78.api.commercecloud.salesforce.com",
diff --git a/packages/test-commerce-sdk-react/package-lock.json b/packages/test-commerce-sdk-react/package-lock.json
index 7cdeca30f1..979fcde646 100644
--- a/packages/test-commerce-sdk-react/package-lock.json
+++ b/packages/test-commerce-sdk-react/package-lock.json
@@ -22,8 +22,8 @@
"typescript": "4.9.5"
},
"engines": {
- "node": "^16.11.0 || ^18.0.0 || ^20.0.0",
- "npm": "^8.0.0 || ^9.0.0 || ^10.0.0"
+ "node": "^16.11.0 || ^18.0.0 || ^20.0.0 || ^22.0.0",
+ "npm": "^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0"
}
},
"node_modules/@babel/runtime": {
diff --git a/packages/test-commerce-sdk-react/package.json b/packages/test-commerce-sdk-react/package.json
index ef33b8ac0c..4c1ae099a7 100644
--- a/packages/test-commerce-sdk-react/package.json
+++ b/packages/test-commerce-sdk-react/package.json
@@ -36,8 +36,8 @@
"typescript": "4.9.5"
},
"engines": {
- "node": "^16.11.0 || ^18.0.0 || ^20.0.0",
- "npm": "^8.0.0 || ^9.0.0 || ^10.0.0"
+ "node": "^16.11.0 || ^18.0.0 || ^20.0.0 || ^22.0.0",
+ "npm": "^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0"
},
"mobify": {
"ssrEnabled": true,
@@ -54,7 +54,7 @@
"**/*.json"
],
"ssrParameters": {
- "ssrFunctionNodeVersion": "20.x",
+ "ssrFunctionNodeVersion": "22.x",
"proxyConfigs": [
{
"host": "kv7kzm78.api.commercecloud.salesforce.com",