chore(e2e): implement asset-resilience with cache-busting retries
Some checks failed
Build & Deploy / 🔍 Prepare (push) Successful in 7s
Build & Deploy / 🧪 QA (push) Successful in 1m5s
Build & Deploy / 🏗️ Build (push) Successful in 2m23s
Build & Deploy / 🚀 Deploy (push) Successful in 16s
Build & Deploy / 🧪 Post-Deploy Verification (push) Failing after 3m48s
Build & Deploy / 🔔 Notify (push) Successful in 3s

This commit is contained in:
2026-04-12 23:06:39 +02:00
parent a38bee9af2
commit d713ef6900

View File

@@ -80,11 +80,48 @@ async function main() {
const page = await browser.newPage();
page.on('console', (msg) => console.log('💻 BROWSER CONSOLE:', msg.text()));
page.on('pageerror', (error) => console.error('💻 BROWSER ERROR:', error.message));
page.on('requestfailed', (request) => {
console.error('💻 BROWSER REQUEST FAILED:', request.url(), request.failure()?.errorText);
let chunkErrorsDetected = false;
page.on('console', (msg) => {
const text = msg.text();
console.log('💻 BROWSER CONSOLE:', text);
if (text.includes('ChunkLoadError') || text.includes('failed to load chunk')) {
chunkErrorsDetected = true;
}
});
page.on('pageerror', (error) => {
console.error('💻 BROWSER ERROR:', error.message);
if (error.message.includes('ChunkLoadError')) {
chunkErrorsDetected = true;
}
});
page.on('requestfailed', (request) => {
const url = request.url();
const failure = request.failure()?.errorText;
console.error('💻 BROWSER REQUEST FAILED:', url, failure);
if (url.endsWith('.js') && (failure === 'net::ERR_ABORTED' || failure?.includes('404'))) {
chunkErrorsDetected = true;
}
});
// Helper for resilient navigation with cache-busting fallback
const navigateWithRetry = async (url: string, label: string) => {
chunkErrorsDetected = false;
console.log(`\n🧪 Testing ${label} on: ${url}`);
// First attempt
await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 30000 });
await delay(2000); // Allow initial JS execution
if (chunkErrorsDetected) {
const cbUrl = `${url}${url.includes('?') ? '&' : '?'}cb=${Date.now()}`;
console.warn(` ⚠️ Assets failed to load (Varnish staleness suspected). Retrying with cache-buster: ${cbUrl}`);
chunkErrorsDetected = false;
await page.goto(cbUrl, { waitUntil: 'domcontentloaded', timeout: 30000 });
}
// Wait for network to settle slightly
await page.waitForNetworkIdle({ idleTime: 500, timeout: 10000 }).catch(() => {});
};
// 3. Authenticate through Gatekeeper login form
try {
@@ -123,13 +160,11 @@ async function main() {
// 4. Test Contact Form
try {
console.log(`\n🧪 Testing Contact Form on: ${contactUrl}`);
await page.goto(contactUrl, { waitUntil: 'networkidle0', timeout: 30000 });
await navigateWithRetry(contactUrl, 'Contact Form');
// Ensure React has hydrated completely - CI runners can be slow
console.log(` ⏳ Waiting for hydration (5s)...`);
await page.evaluate(() => new Promise((resolve) => setTimeout(resolve, 5000)));
await page.waitForNetworkIdle({ idleTime: 1000, timeout: 20000 }).catch(() => {});
await delay(5000);
// Ensure form is visible and interactive
try {
@@ -191,13 +226,11 @@ async function main() {
// 4. Test Product Quote Form
try {
console.log(`\n🧪 Testing Product Quote Form on: ${productUrl}`);
await page.goto(productUrl, { waitUntil: 'networkidle0', timeout: 30000 });
await navigateWithRetry(productUrl, 'Product Quote Form');
// Ensure React has hydrated completely
console.log(` ⏳ Waiting for hydration (5s)...`);
await page.evaluate(() => new Promise((resolve) => setTimeout(resolve, 5000)));
await page.waitForNetworkIdle({ idleTime: 1000, timeout: 20000 }).catch(() => {});
await delay(5000);
// The product form uses dynamic IDs, so we select by input type in the specific form context
try {