Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
c36c896
playwright tests
jeremy-jung1 Jun 25, 2025
cae80a9
variable name change
jeremy-jung1 Jun 25, 2025
98d6d75
Create ssr.test.js
jeremy-jung1 Jun 27, 2025
14519ee
fix the tests
jeremy-jung1 Jun 27, 2025
ef7c280
Update CHANGELOG.md
jeremy-jung1 Jun 27, 2025
f6940b0
Only keep tests relevant to the feature
jeremy-jung1 Jun 27, 2025
8b1397c
Remove unused vars
jeremy-jung1 Jun 27, 2025
de564d8
Merge branch 'develop' into W-18685522-reset-and-passwordless-integra…
jeremy-jung1 Jun 27, 2025
dceb6d9
Linting
jeremy-jung1 Jun 27, 2025
f108b78
More linting
jeremy-jung1 Jun 27, 2025
da85267
Try auto sync and deploy
jeremy-jung1 Jun 30, 2025
a2cbaf2
for some reason need to update the commerce-sdk-react changelog. will…
jeremy-jung1 Jun 30, 2025
d73e3c9
Try adding branch to dependency to test
jeremy-jung1 Jun 30, 2025
ecd734d
Try adding perms and removing notifications
jeremy-jung1 Jun 30, 2025
7203712
Go to template retail react app
jeremy-jung1 Jun 30, 2025
c1e5387
Update project slug
jeremy-jung1 Jun 30, 2025
f8ad75c
log some more info in push mrt
jeremy-jung1 Jun 30, 2025
9c24f62
Make some updates
jeremy-jung1 Jul 1, 2025
b11782f
Update yml file
jeremy-jung1 Jul 1, 2025
eb4a480
Change env name
jeremy-jung1 Jul 2, 2025
52cec86
Update branch name
jeremy-jung1 Jul 2, 2025
502faa0
Update variable
jeremy-jung1 Jul 2, 2025
5722000
Remove unnecessary changes
jeremy-jung1 Jul 2, 2025
07fe23e
Need to update changelog for some reason
jeremy-jung1 Jul 2, 2025
02fa18f
Testing issue creation
jeremy-jung1 Jul 2, 2025
4ee2253
Just testing
jeremy-jung1 Jul 2, 2025
b363136
Update sync_extra_features_e2e.yml
jeremy-jung1 Jul 2, 2025
f0e4e03
Add creation
jeremy-jung1 Jul 2, 2025
b3f5f21
Revert the tests
jeremy-jung1 Jul 2, 2025
ecd8171
Update message in issue creation
jeremy-jung1 Jul 2, 2025
d33ca67
Merge branch 'develop' into W-18685522-reset-and-passwordless-integra…
jeremy-jung1 Jul 2, 2025
6cc46e7
Remove this branch from dependency
jeremy-jung1 Jul 2, 2025
53f2dc1
Merge branch 'W-18685522-reset-and-passwordless-integration-test' of …
jeremy-jung1 Jul 2, 2025
1c96b6a
Remove force sync
jeremy-jung1 Jul 2, 2025
505f0af
Add tests for when extra login features are not enabled
jeremy-jung1 Jul 3, 2025
70247cf
Apply some feedback
jeremy-jung1 Jul 4, 2025
e3cfcb4
Update e2e.yml
jeremy-jung1 Jul 4, 2025
ec85ce8
Update command and comment some things for test
jeremy-jung1 Jul 4, 2025
f6d34f0
Update e2e.yml
jeremy-jung1 Jul 4, 2025
929d86c
Update e2e.yml
jeremy-jung1 Jul 4, 2025
10aa890
Try to insert these env vars
jeremy-jung1 Jul 4, 2025
2c94bc0
Apply feedback
jeremy-jung1 Jul 4, 2025
2ede681
Update playwright.config.js
jeremy-jung1 Jul 4, 2025
9909caa
Update separate mobile and desktop
jeremy-jung1 Jul 4, 2025
0ab3fde
typo
jeremy-jung1 Jul 4, 2025
6f59650
Fix the sites
jeremy-jung1 Jul 6, 2025
4caf056
Update config.js
jeremy-jung1 Jul 6, 2025
be5b871
Remove changes made for just testing
jeremy-jung1 Jul 7, 2025
e584cdd
Merge branch 'develop' into W-18685522-reset-and-passwordless-integra…
jeremy-jung1 Jul 7, 2025
9de4b67
Remove dev only change
jeremy-jung1 Jul 8, 2025
6395135
Merge branch 'develop' into W-18685522-reset-and-passwordless-integra…
jeremy-jung1 Jul 8, 2025
0123c9e
Merge branch 'develop' into W-18685522-reset-and-passwordless-integra…
jeremy-jung1 Jul 8, 2025
d3b026c
Merge branch 'develop' into W-18685522-reset-and-passwordless-integra…
jeremy-jung1 Jul 8, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion e2e/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -162,5 +162,5 @@ module.exports = {
},
PWA_E2E_USER_EMAIL: process.env.PWA_E2E_USER_EMAIL,
PWA_E2E_USER_PASSWORD: process.env.PWA_E2E_USER_PASSWORD,
SOCIAL_LOGIN_RETAIL_APP_HOME: "https://wasatch-mrt-feature-public.mrt-storefront-staging.com"
MORE_LOGIN_OPTIONS_RETAIL_APP_HOME: "https://wasatch-mrt-feature-private.mrt-storefront-staging.com"
Copy link
Collaborator

@hajinsuha1 hajinsuha1 Jun 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would we want to use an environment deployed in a pwa kit owned environment to make sure it doesnt get lost or deleted? I see in CI it uses this one:

run: export RETAIL_APP_HOME=https://scaffold-pwa-e2e-pwa-kit-private.mobify-storefront.com/

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also would we consider using a more generic name for the constant like RETAIL_REACT_APP_HOME_PRIVATE_CLIENT so it can be used for other private client E2E tests in the future?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The RETAIL_APP_HOME doesn't have social and passwordless enabled, so consolidating on one site will lose us an E2E test "branch" of the PWA kit site configured without the social and passwordless changes, which has an impact on the UI. Right now we have two sites: one with the additional login features and one not, and I thought that was a good variety of sites.

I can make the deployment on the pwa-kit environment instead to make it more visible

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh sorry I meant, it looks like there are 2 PWA Kit sites:

Was wondering if we should reuse https://scaffold-pwa-e2e-pwa-kit-private.mobify-storefront.com instead of creating a new one in the PWA Kit project

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we want to keep the tests for the old login paths then we should create a new site. https://scaffold-pwa-e2e-pwa-kit-private.mobify-storefront.com/ is the one that the e2e tests get executed on. The current e2e tests for shopper login assumes the UI for these new login features are turned off.

The new tests in this PR work on a UI where the passwordless login is enabled, so it has to go on a separate site. If we reuse a site, then we will lose the e2e test "coverage" on the old configuration without the features enabled.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah I think Jinsu is suggesting using the scaffold-pwa project because that is internal use only - so external non-PWA folks cannot alter or delete the environments

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated the environment to be in scaffold-pwa and change the variable name to include other features that are defaulted to be off.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jeremy-jung1 I know you already created the env, but is there potentially a better name that describes the configuration of the env?

I had originally thought the difference with this env vs the original e2e env is that it’s configured with a SLAS private client

Copy link
Collaborator Author

@jeremy-jung1 jeremy-jung1 Jul 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new environment is called EXTRA_FEATURES_E2E_RETAIL_APP_HOME. Instead of just features that has to be configured with SLAS Private Client, I thought a more encompassing name for features that are off by default would be good. Some features in the future might be dependent on other conditions. Social login is default to disabled too, but that isn't dependent on SLAS Private Client.

};
4 changes: 2 additions & 2 deletions e2e/scripts/pageHelpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ export const navigateToPDPDesktopSocial = async ({
productColor,
productPrice
}) => {
await page.goto(config.SOCIAL_LOGIN_RETAIL_APP_HOME)
await page.goto(config.MORE_LOGIN_OPTIONS_RETAIL_APP_HOME)
await answerConsentTrackingForm(page)

await page.getByRole('link', {name: 'Womens'}).hover()
Expand Down Expand Up @@ -373,7 +373,7 @@ export const loginShopper = async ({page, userCredentials}) => {
*/
export const socialLoginShopper = async ({page}) => {
try {
await page.goto(config.SOCIAL_LOGIN_RETAIL_APP_HOME + '/login')
await page.goto(config.MORE_LOGIN_OPTIONS_RETAIL_APP_HOME + '/login')

await page.getByText(/Google/i).click()
await expect(page.getByText(/Sign in with Google/i)).toBeVisible({timeout: 10000})
Expand Down
107 changes: 107 additions & 0 deletions e2e/tests/desktop/login.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
/*
* Copyright (c) 2025, 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')
const {generateUserCredentials} = require('../../scripts/utils.js')
const {answerConsentTrackingForm} = require('../../scripts/pageHelpers.js')

const GUEST_USER_CREDENTIALS = generateUserCredentials()
/**
* Test that a user can login with passwordless login on mobile. There is no programmatic way to check the email,
* so we will check that the necessary API call is being made and expected UI is shown
*/
test('Verify passwordless login request', async ({page}) => {
let interceptedRequest = null

await page.route('**/mobify/slas/private/shopper/auth/v1/organizations/*/oauth2/passwordless/login', (route) => {
interceptedRequest = route.request()
route.continue()
})

await page.goto(config.MORE_LOGIN_OPTIONS_RETAIL_APP_HOME + '/login')
await answerConsentTrackingForm(page)

await page.locator('#email').scrollIntoViewIfNeeded()
await page.fill('#email', config.PWA_E2E_USER_EMAIL)

await page.getByRole('button', {name: 'Continue Securely'}).click()

await page.waitForResponse('**/mobify/slas/private/shopper/auth/v1/organizations/*/oauth2/passwordless/login')

expect(interceptedRequest).toBeTruthy()
expect(interceptedRequest.method()).toBe('POST')

const postData = interceptedRequest.postData()
expect(postData).toBeTruthy()

const params = new URLSearchParams(postData)

expect(params.get('user_id')).toBe(config.PWA_E2E_USER_EMAIL)
expect(params.get('mode')).toBe('callback')
expect(params.get('channel_id')).toBe('RefArchGlobal')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move the siteID to config as well. Incase we need to move the site we're pointing to.

expect(params.get('callback_uri')).toMatch(/.*\/passwordless-login-callback$/)
})

test('Verify password reset callback request', async ({page}) => {
let interceptedRequest = null

await page.route('**/mobify/slas/private/shopper/auth/v1/organizations/*/oauth2/password/reset', (route) => {
interceptedRequest = route.request()
route.continue()
})

await page.goto(config.MORE_LOGIN_OPTIONS_RETAIL_APP_HOME + '/login')
await answerConsentTrackingForm(page)

await page.locator('#email').scrollIntoViewIfNeeded()
await page.fill('#email', config.PWA_E2E_USER_EMAIL)

await page.getByRole('button', {name: 'Password'}).click()
await page.getByRole('button', {name: 'Forgot password?'}).click()

await page.fill('#email', config.PWA_E2E_USER_EMAIL)
await page.getByRole('button', {name: 'Reset Password'}).click()

await page.waitForResponse('**/mobify/slas/private/shopper/auth/v1/organizations/*/oauth2/password/reset')

expect(interceptedRequest).toBeTruthy()
expect(interceptedRequest.method()).toBe('POST')

const postData = interceptedRequest.postData()
expect(postData).toBeTruthy()

const params = new URLSearchParams(postData)

expect(params.get('user_id')).toBe(config.PWA_E2E_USER_EMAIL)
expect(params.get('mode')).toBe('callback')
expect(params.get('channel_id')).toBe('RefArchGlobal')
expect(params.get('callback_uri')).toMatch(/.*\/reset-password-callback$/)
expect(params.get('hint')).toBe('cross_device')
})

test('Verify password reset request', async ({page}) => {
let interceptedRequest = null
await page.route('**/mobify/slas/private/shopper/auth/v1/organizations/*/oauth2/password/action', (route) => {
interceptedRequest = route.request()
route.continue()
})

await page.goto(config.MORE_LOGIN_OPTIONS_RETAIL_APP_HOME + `/reset-password-landing?token=1234567&email=${GUEST_USER_CREDENTIALS.email}`)
await answerConsentTrackingForm(page)

await page.fill('#password', GUEST_USER_CREDENTIALS.password)
await page.fill('#confirmPassword', GUEST_USER_CREDENTIALS.password)

expect(await page.inputValue('#password')).toBe(GUEST_USER_CREDENTIALS.password)
expect(await page.inputValue('#confirmPassword')).toBe(GUEST_USER_CREDENTIALS.password)
await page.getByRole('button', {name: 'Reset Password'}).click()

await page.waitForResponse('**/mobify/slas/private/shopper/auth/v1/organizations/*/oauth2/password/action')

expect(interceptedRequest).toBeTruthy()
})
120 changes: 120 additions & 0 deletions e2e/tests/mobile/login.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
/*
* Copyright (c) 2025, 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')
const {generateUserCredentials} = require('../../scripts/utils.js')
const {answerConsentTrackingForm} = require('../../scripts/pageHelpers.js')

const GUEST_USER_CREDENTIALS = generateUserCredentials()

/**
* Test that a user can login with passwordless login on mobile. There is no programmatic way to check the email,
* so we will check that the necessary API call is being made and expected UI is shown
*/
test('Verify passwordless login request on mobile', async ({page}) => {
let interceptedRequest = null

await page.route('**/mobify/slas/private/shopper/auth/v1/organizations/*/oauth2/passwordless/login', (route) => {
interceptedRequest = route.request()
route.continue()
})

await page.goto(config.MORE_LOGIN_OPTIONS_RETAIL_APP_HOME + '/login')
await answerConsentTrackingForm(page)

await page.locator('#email').scrollIntoViewIfNeeded()
await page.fill('#email', config.PWA_E2E_USER_EMAIL)

await page.getByRole('button', {name: 'Continue Securely'}).scrollIntoViewIfNeeded()
await page.getByRole('button', {name: 'Continue Securely'}).click()

await page.waitForResponse('**/mobify/slas/private/shopper/auth/v1/organizations/*/oauth2/passwordless/login')

expect(interceptedRequest).toBeTruthy()
expect(interceptedRequest.method()).toBe('POST')

const postData = interceptedRequest.postData()
expect(postData).toBeTruthy()

const params = new URLSearchParams(postData)

expect(params.get('user_id')).toBe(config.PWA_E2E_USER_EMAIL)
expect(params.get('mode')).toBe('callback')
expect(params.get('channel_id')).toBe('RefArchGlobal')
expect(params.get('callback_uri')).toMatch(/.*\/passwordless-login-callback$/)
})

test('Verify password reset callback request on mobile', async ({page}) => {
let interceptedRequest = null

await page.route('**/mobify/slas/private/shopper/auth/v1/organizations/*/oauth2/password/reset', (route) => {
interceptedRequest = route.request()
route.continue()
})

await page.goto(config.MORE_LOGIN_OPTIONS_RETAIL_APP_HOME + '/login')
await answerConsentTrackingForm(page)

await page.locator('#email').scrollIntoViewIfNeeded()
await page.fill('#email', config.PWA_E2E_USER_EMAIL)

await page.getByRole('button', {name: 'Password'}).scrollIntoViewIfNeeded()
await page.getByRole('button', {name: 'Password'}).click()

await page.getByRole('button', {name: 'Forgot password?'}).scrollIntoViewIfNeeded()
await page.getByRole('button', {name: 'Forgot password?'}).click()

await page.locator('#email').scrollIntoViewIfNeeded()
await page.fill('#email', config.PWA_E2E_USER_EMAIL)

await page.getByRole('button', {name: 'Reset Password'}).scrollIntoViewIfNeeded()
await page.getByRole('button', {name: 'Reset Password'}).click()

await page.waitForResponse('**/mobify/slas/private/shopper/auth/v1/organizations/*/oauth2/password/reset')

expect(interceptedRequest).toBeTruthy()
expect(interceptedRequest.method()).toBe('POST')

const postData = interceptedRequest.postData()
expect(postData).toBeTruthy()

const params = new URLSearchParams(postData)

expect(params.get('user_id')).toBe(config.PWA_E2E_USER_EMAIL)
expect(params.get('mode')).toBe('callback')
expect(params.get('channel_id')).toBe('RefArchGlobal')
expect(params.get('callback_uri')).toMatch(/.*\/reset-password-callback$/)
expect(params.get('hint')).toBe('cross_device')
})

test('Verify password reset request on mobile', async ({page}) => {
let interceptedRequest = null
await page.route('**/mobify/slas/private/shopper/auth/v1/organizations/*/oauth2/password/action', (route) => {
interceptedRequest = route.request()
route.continue()
})

await page.goto(config.MORE_LOGIN_OPTIONS_RETAIL_APP_HOME + `/reset-password-landing?token=1234567&email=${GUEST_USER_CREDENTIALS.email}`)
await answerConsentTrackingForm(page)

await page.locator('#password').scrollIntoViewIfNeeded()
await page.fill('#password', GUEST_USER_CREDENTIALS.password)

await page.locator('#confirmPassword').scrollIntoViewIfNeeded()
await page.fill('#confirmPassword', GUEST_USER_CREDENTIALS.password)

expect(await page.inputValue('#password')).toBe(GUEST_USER_CREDENTIALS.password)
expect(await page.inputValue('#confirmPassword')).toBe(GUEST_USER_CREDENTIALS.password)

await page.getByRole('button', {name: 'Reset Password'}).scrollIntoViewIfNeeded()
await page.getByRole('button', {name: 'Reset Password'}).click()

await page.waitForResponse('**/mobify/slas/private/shopper/auth/v1/organizations/*/oauth2/password/action')

expect(interceptedRequest).toBeTruthy()
})
1 change: 1 addition & 0 deletions packages/template-retail-react-app/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
- [a11y] Ensure voiceover announces contents of the email confirmation modal [#2540](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/2540)
- Updated 6 new languages [#2495](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/2495)
- Fix Einstein event tracking for `addToCart` event [#2558](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/2558)
- Password Reset and Passwordless Integration Test [#2669](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/2669)


## v6.1.0 (May 22, 2025)
Expand Down
Loading