-
Notifications
You must be signed in to change notification settings - Fork 212
@W-18685522 Password Reset and Passwordless Integration Test #2669
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
jeremy-jung1
merged 53 commits into
develop
from
W-18685522-reset-and-passwordless-integration-test
Jul 8, 2025
Merged
Changes from 7 commits
Commits
Show all changes
53 commits
Select commit
Hold shift + click to select a range
c36c896
playwright tests
jeremy-jung1 cae80a9
variable name change
jeremy-jung1 98d6d75
Create ssr.test.js
jeremy-jung1 14519ee
fix the tests
jeremy-jung1 ef7c280
Update CHANGELOG.md
jeremy-jung1 f6940b0
Only keep tests relevant to the feature
jeremy-jung1 8b1397c
Remove unused vars
jeremy-jung1 de564d8
Merge branch 'develop' into W-18685522-reset-and-passwordless-integra…
jeremy-jung1 dceb6d9
Linting
jeremy-jung1 f108b78
More linting
jeremy-jung1 da85267
Try auto sync and deploy
jeremy-jung1 a2cbaf2
for some reason need to update the commerce-sdk-react changelog. will…
jeremy-jung1 d73e3c9
Try adding branch to dependency to test
jeremy-jung1 ecd734d
Try adding perms and removing notifications
jeremy-jung1 7203712
Go to template retail react app
jeremy-jung1 c1e5387
Update project slug
jeremy-jung1 f8ad75c
log some more info in push mrt
jeremy-jung1 9c24f62
Make some updates
jeremy-jung1 b11782f
Update yml file
jeremy-jung1 eb4a480
Change env name
jeremy-jung1 52cec86
Update branch name
jeremy-jung1 502faa0
Update variable
jeremy-jung1 5722000
Remove unnecessary changes
jeremy-jung1 07fe23e
Need to update changelog for some reason
jeremy-jung1 02fa18f
Testing issue creation
jeremy-jung1 4ee2253
Just testing
jeremy-jung1 b363136
Update sync_extra_features_e2e.yml
jeremy-jung1 f0e4e03
Add creation
jeremy-jung1 b3f5f21
Revert the tests
jeremy-jung1 ecd8171
Update message in issue creation
jeremy-jung1 d33ca67
Merge branch 'develop' into W-18685522-reset-and-passwordless-integra…
jeremy-jung1 6cc46e7
Remove this branch from dependency
jeremy-jung1 53f2dc1
Merge branch 'W-18685522-reset-and-passwordless-integration-test' of …
jeremy-jung1 1c96b6a
Remove force sync
jeremy-jung1 505f0af
Add tests for when extra login features are not enabled
jeremy-jung1 70247cf
Apply some feedback
jeremy-jung1 e3cfcb4
Update e2e.yml
jeremy-jung1 ec85ce8
Update command and comment some things for test
jeremy-jung1 f6d34f0
Update e2e.yml
jeremy-jung1 929d86c
Update e2e.yml
jeremy-jung1 10aa890
Try to insert these env vars
jeremy-jung1 2c94bc0
Apply feedback
jeremy-jung1 2ede681
Update playwright.config.js
jeremy-jung1 9909caa
Update separate mobile and desktop
jeremy-jung1 0ab3fde
typo
jeremy-jung1 6f59650
Fix the sites
jeremy-jung1 4caf056
Update config.js
jeremy-jung1 be5b871
Remove changes made for just testing
jeremy-jung1 e584cdd
Merge branch 'develop' into W-18685522-reset-and-passwordless-integra…
jeremy-jung1 9de4b67
Remove dev only change
jeremy-jung1 6395135
Merge branch 'develop' into W-18685522-reset-and-passwordless-integra…
jeremy-jung1 0123c9e
Merge branch 'develop' into W-18685522-reset-and-passwordless-integra…
jeremy-jung1 d3b026c
Merge branch 'develop' into W-18685522-reset-and-passwordless-integra…
jeremy-jung1 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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') | ||
|
||
| 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() | ||
| }) | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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() | ||
| }) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
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:
pwa-kit/.github/workflows/e2e.yml
Line 374 in 8417719
There was a problem hiding this comment.
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_CLIENTso it can be used for other private client E2E tests in the future?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The
RETAIL_APP_HOMEdoesn'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
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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-pwaproject because that is internal use only - so external non-PWA folks cannot alter or delete the environmentsThere was a problem hiding this comment.
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-pwaand change the variable name to include other features that are defaulted to be off.There was a problem hiding this comment.
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
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
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.