Skip to content
Merged
Show file tree
Hide file tree
Changes from 33 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
186 changes: 186 additions & 0 deletions .github/workflows/sync_extra_features_e2e.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
name: Sync More Logins E2E Branch with Develop

on:
# Trigger when develop branch is updated
push:
branches:
- develop
# Run daily at 11 PM PST (7 AM UTC) to catch any missed syncs
schedule:
- cron: '0 7 * * *'
# Allow manual triggering with options
workflow_dispatch:
inputs:
force_sync:
description: 'Force sync even if conflicts exist (overwrites E2E branch)'
required: false
default: false
type: boolean

permissions:
contents: write
issues: write
pull-requests: read

jobs:
sync-branch:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}

- name: Configure git
run: |
git config --global user.name ${{ secrets.GIT_CONFIG_USERNAME }}
git config --global user.email ${{ secrets.GIT_CONFIG_EMAIL }}

- name: Sync extra-features-e2e-branch with develop
id: sync
continue-on-error: true
run: |
set -e

# Fetch all branches
git fetch origin

# Check if the target branch exists
if ! git show-ref --verify --quiet refs/remotes/origin/extra-features-e2e-branch; then
echo "Branch extra-features-e2e-branch does not exist. Creating it from develop..."
git checkout -b extra-features-e2e-branch origin/develop
git push origin extra-features-e2e-branch
echo "✅ Created extra-features-e2e-branch branch from develop"
echo "status=created" >> $GITHUB_OUTPUT
exit 0
fi

# Switch to the target branch
git checkout extra-features-e2e-branch
git reset --hard origin/extra-features-e2e-branch

# Check if we're already up to date
if git merge-base --is-ancestor origin/develop HEAD; then
echo "✅ extra-features-e2e-branch is already up to date with develop"
echo "status=up-to-date" >> $GITHUB_OUTPUT
exit 0
fi

if [ "${{ github.event.inputs.force_sync }}" = "true" ]; then
echo "🔧 Force sync requested. Resetting to develop..."
git reset --hard origin/develop
git push --force origin extra-features-e2e-branch
echo "⚠️ Force synced extra-features-e2e-branch with develop (all conflicts overwritten)"
echo "status=force-synced" >> $GITHUB_OUTPUT
else
# Default merge strategy
if git merge origin/develop --no-edit; then
echo "✅ Successfully merged develop into extra-features-e2e-branch"
git push origin extra-features-e2e-branch
echo "status=merged" >> $GITHUB_OUTPUT
else
echo "❌ Merge conflicts detected!"
echo "📋 Files with conflicts:"
git diff --name-only --diff-filter=U || true
git merge --abort
echo "status=conflict" >> $GITHUB_OUTPUT
exit 1
fi
fi

- name: Create conflict resolution issue
if: steps.sync.outputs.status == 'conflict'
uses: actions/github-script@v7
with:
script: |
const conflictFiles = `${{ steps.sync.outputs.conflict_files || 'Unknown files' }}`;
const issueBody = `
## 🚨 Automatic Sync Failed - Merge Conflicts Detected

Some features in PWA kit are defaulted to be off in \`develop\` branch (e.g. if they only work with private client).
Hence there is another site that has these features enabled that E2E tests of these extra features are run against.
The \`extra-features-e2e-branch\` is used for this site.

A job is run nightly to sync \`develop\` to \`extra-features-e2e-branch\` branch, but today this automatic sync from \`develop\` to \`extra-features-e2e-branch\` failed due to merge conflicts.

### Conflicting Files:
\`\`\`
${conflictFiles}
\`\`\`


### Manual Resolution:
\`\`\`bash
git checkout extra-features-e2e-branch
git pull origin extra-features-e2e-branch
git merge develop
# Resolve conflicts manually
git add .
git commit -m "Resolve merge conflicts from develop"
git push origin extra-features-e2e-branch
\`\`\`

### After resolving the conflicts, close this issue
`;

// Check if issue already exists
const existingIssues = await github.rest.issues.listForRepo({
owner: context.repo.owner,
repo: context.repo.repo,
state: 'open',
labels: 'sync-conflict'
});

if (existingIssues.data.length === 0) {
await github.rest.issues.create({
owner: context.repo.owner,
repo: context.repo.repo,
title: '🚨 Extra Features E2E Branch Sync Conflict - Manual Resolution Required',
body: issueBody,
labels: ['sync-conflict', 'automation']
});
}

deploy:
needs: sync-branch
if: needs.sync-branch.outputs.status != 'conflict' && needs.sync-branch.outputs.status != 'up-to-date'
runs-on: ubuntu-latest
environment: extra-features-e2e

steps:
- name: Checkout extra-features-e2e-branch branch
uses: actions/checkout@v4
with:
ref: extra-features-e2e-branch

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 22
cache: 'npm'

- name: Install Monorepo Dependencies
run: |
# Install node dependencies
node ./scripts/gtime.js monorepo_install npm ci

- name: Build project
run: |
cd packages/template-retail-react-app
npm run build

- name: Create MRT credentials file
uses: "./.github/actions/create_mrt"
with:
mobify_user: ${{ secrets.MOBIFY_CLIENT_USER }}
mobify_api_key: ${{ secrets.MOBIFY_CLIENT_API_KEY }}

- name: Deploy to MRT
uses: "./.github/actions/push_to_mrt"
with:
CWD: "./packages/template-retail-react-app"
TARGET: extra-features-e2e
PROJECT: scaffold-pwa
MESSAGE: "Auto-sync from develop - build ${{ github.run_id }} (${{ github.sha }})"
FLAGS: --wait
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"
EXTRA_FEATURES_E2E_RETAIL_APP_HOME: "https://scaffold-pwa-extra-features-e2e.mobify-storefront.com"
};
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.EXTRA_FEATURES_E2E_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.EXTRA_FEATURES_E2E_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.EXTRA_FEATURES_E2E_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.EXTRA_FEATURES_E2E_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.EXTRA_FEATURES_E2E_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()
})
Loading
Loading