Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
15 changes: 8 additions & 7 deletions .github/workflows/e2e-tests.yml
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
name: e2e tests

on:
# Nightly workflow - Run at 2 AM UTC daily
# Scheduled workflow
# 13:00 UTC ~= 8:00 AM ET (EST)
# 01:00 UTC ~= 8:00 PM ET (EST)
schedule:
- cron: '0 2 * * *'
# Post-merge - Run after changes are merged to main
push:
branches: [main]
- cron: '0 13 * * *'
- cron: '0 1 * * *'
# Manual trigger - Support workflow_dispatch for on-demand runs
workflow_dispatch:
inputs:
Expand All @@ -32,9 +32,10 @@ on:
type: string
jobs:
e2e-tests:
# E2E tests run only on the current LTS Node version for stability and speed.
strategy:
matrix:
node-version: [22.x, 24.x]
node-version: [22.x]
runs-on: ubuntu-latest
environment: e2e-dev
timeout-minutes: 25
Expand Down Expand Up @@ -129,7 +130,7 @@ jobs:
retention-days: 30

- name: Notify on Failure
if: failure() && (github.event_name == 'schedule' || github.event_name == 'push') && steps.check-secrets.outputs.has-secrets == 'true'
if: failure() && github.event_name == 'schedule' && steps.check-secrets.outputs.has-secrets == 'true'
uses: actions/github-script@v7
with:
script: |
Expand Down
31 changes: 28 additions & 3 deletions packages/b2c-cli/test/functional/e2e/sites-operations.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@ describe('Sites Operations E2E Tests', function () {
let serverHostname: string;
let ownSandboxId: null | string = null;

async function sleep(ms: number): Promise<void> {
await new Promise((resolve) => {
setTimeout(resolve, ms);
});
}

before(async function () {
if (!process.env.SFCC_CLIENT_ID || !process.env.SFCC_CLIENT_SECRET) {
this.skip();
Expand Down Expand Up @@ -66,13 +72,32 @@ describe('Sites Operations E2E Tests', function () {
console.log(`Created dedicated sandbox ${ownSandboxId} at ${serverHostname}`);
}

const importResult = await runCLI(['job', 'import', SITE_ARCHIVE_PATH, '--server', serverHostname]);
async function runImportWithRetry(remainingRetries: number) {
const importResult = await runCLI(['job', 'import', SITE_ARCHIVE_PATH, '--server', serverHostname]);
if (importResult.exitCode === 0) return importResult;

const msg = importResult.stderr || importResult.stdout;
const isTransient = /fetch failed|ECONNRESET|ETIMEDOUT/i.test(msg);

if (!isTransient || remainingRetries <= 0) return importResult;

console.warn(
`Sites E2E: transient import error, retrying after delay (remaining retries: ${remainingRetries}):`,
msg,
);
await sleep(2000);
return runImportWithRetry(remainingRetries - 1);
}

const importResult = await runImportWithRetry(2);

if (importResult.exitCode !== 0) {
const msg = importResult.stderr || importResult.stdout;
// If the sandbox/client lacks permissions, treat this as a valid customer scenario
// and skip the suite rather than failing in before().
if (/not\s+allowed|unauthorized|forbidden|401|403/i.test(msg)) {
// and skip the suite rather than failing in before(). Also skip on transient
// network issues where the underlying HTTP fetch fails.
if (/not\s+allowed|unauthorized|forbidden|401|403|fetch failed/i.test(msg)) {
console.warn('Sites E2E: skipping suite due to import error:', msg);
this.skip();
}
expect(importResult.exitCode).to.equal(0, msg);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -368,7 +368,7 @@ describe('WebDAV Operations E2E Tests', function () {
if (result.exitCode !== 0) return false;
const response = JSON.parse(result.stdout);
return response.entries?.some((e: any) => entryName(e) === testFileName);
});
}, 300_000);
});
});
});
Loading