diff --git a/docker-compose.yml b/docker-compose.yml index bbafef7d..38b51df1 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -29,7 +29,7 @@ services: - "traefik.http.routers.${PROJECT_NAME:-klz}.middlewares=${AUTH_MIDDLEWARE:-klz-ratelimit,klz-forward,klz-compress}" # Public Router โ€“ paths that bypass Gatekeeper auth (health, SEO, static assets, OG images) - - "traefik.http.routers.${PROJECT_NAME:-klz}-public.rule=(${TRAEFIK_HOST_RULE:-Host(`${TRAEFIK_HOST:-klz-cables.com}`)}) && (PathPrefix(`/_next/static`) || PathPrefix(`/_next/data`) || PathPrefix(`/_next/image`) || PathPrefix(`/health`) || PathPrefix(`/login`) || PathPrefix(`/gatekeeper`) || PathPrefix(`/uploads`) || PathPrefix(`/media`) || Path(`/robots.txt`) || Path(`/manifest.webmanifest`) || PathPrefix(`/sitemap`) || PathPrefix(`/api/og`) || PathPrefix(`/opengraph-image`) || PathRegexp(`^/([a-z]{2}/)?(health|login|gatekeeper|uploads|media|robots\\\\.txt|sitemap|api/og|opengraph-image)`))" + - "traefik.http.routers.${PROJECT_NAME:-klz}-public.rule=(${TRAEFIK_HOST_RULE:-Host(`${TRAEFIK_HOST:-klz-cables.com}`)}) && (PathPrefix(`/_next`) || PathPrefix(`/health`) || PathPrefix(`/login`) || PathPrefix(`/gatekeeper`) || PathPrefix(`/uploads`) || PathPrefix(`/media`) || Path(`/robots.txt`) || Path(`/manifest.webmanifest`) || PathPrefix(`/sitemap`) || PathPrefix(`/api/og`) || PathPrefix(`/opengraph-image`) || PathRegexp(`^/([a-z]{2}/)?(health|login|gatekeeper|uploads|media|robots\\\\.txt|sitemap|api/og|opengraph-image)`))" - "traefik.http.routers.${PROJECT_NAME:-klz}-public.entrypoints=${TRAEFIK_ENTRYPOINT:-web}" - "traefik.http.routers.${PROJECT_NAME:-klz}-public.tls.certresolver=${TRAEFIK_CERT_RESOLVER:-}" - "traefik.http.routers.${PROJECT_NAME:-klz}-public.tls=${TRAEFIK_TLS:-false}" diff --git a/scripts/check-forms.ts b/scripts/check-forms.ts index 6217b4ce..74db8d2b 100644 --- a/scripts/check-forms.ts +++ b/scripts/check-forms.ts @@ -11,9 +11,37 @@ const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); async function main() { console.log(`\n๐Ÿš€ Starting E2E Form Submission Check for: ${targetUrl}`); - // 0. Settlement Delay: Wait for deployment to settle (sync containers/Varnish) - console.log(`โณ Waiting 10s for deployment settlement...`); - await delay(10000); + // 0. Pre-warming settlement: Wait for deployment to respond (sync containers/Varnish) + console.log(`โณ Pre-warming: Waiting for deployment to return 200 OK...`); + const maxWaitMs = 60000; + const startTime = Date.now(); + let warmed = false; + + while (Date.now() - startTime < maxWaitMs) { + try { + const resp = await axios.get(targetUrl, { + headers: { Cookie: `klz_gatekeeper_session=${gatekeeperPassword}` }, + timeout: 5000, + validateStatus: (s) => s === 200, + }); + if (resp.status === 200) { + warmed = true; + break; + } + } catch (e) { + // Quietly retry + } + await delay(2000); + } + + if (!warmed) { + console.warn(`โš ๏ธ Pre-warming timed out after 60s. Proceeding anyway...`); + } else { + console.log(`โœ… Deployment settled and responding.`); + } + + // Brief stabilization buffer + await delay(5000); // 1. Fetch Sitemap to discover the contact page and a product page const sitemapUrl = `${targetUrl.replace(/\/$/, '')}/sitemap.xml`; @@ -126,19 +154,29 @@ async function main() { chunkErrorsDetected = false; console.log(`\n๐Ÿงช Testing ${label} on: ${url}`); - // First attempt - await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 30000 }); - await delay(3000); // Allow initial JS execution + // First attempt: Wait for network to be relatively idle + await page.goto(url, { waitUntil: 'networkidle2', timeout: 30000 }); - 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 }); + // REDIRECTION CHECK: Logging redirected landing page + const finalUrl = page.url(); + if (finalUrl !== url && !finalUrl.includes(url)) { + console.log(` ๐Ÿ”€ Redirected to: ${finalUrl}`); } - // Wait for network to settle slightly - await page.waitForNetworkIdle({ idleTime: 1000, timeout: 10000 }).catch(() => {}); + if (chunkErrorsDetected) { + const buster = `cb=${Date.now()}`; + const cbUrl = finalUrl.includes('?') ? `${finalUrl}&${buster}` : `${finalUrl}?${buster}`; + console.warn(` โš ๏ธ Assets failed to load (Varnish staleness suspected). Retrying with cache-buster: ${cbUrl}`); + chunkErrorsDetected = false; + await page.goto(cbUrl, { waitUntil: 'networkidle2', timeout: 30000 }); + } + + // Capture HTML on failure during hydration wait + try { + await page.waitForNetworkIdle({ idleTime: 1000, timeout: 5000 }).catch(() => {}); + } catch (e) { + console.warn(' โš ๏ธ Network idle timeout, proceeding with current state.'); + } }; // 3. Authenticate through Gatekeeper login form @@ -189,7 +227,9 @@ async function main() { // Find the form input by name await page.waitForSelector('input[name="name"]', { visible: true, timeout: 15000 }); } catch (e) { - console.error('Failed to find Contact Form input. Page Title:', await page.title()); + console.error('โŒ Failed to find Contact Form input. Page Title:', await page.title()); + const html = await page.content(); + console.log(`๐Ÿ’ป FULL HTML DUMP (top 2000 chars):\n${html.slice(0, 2000)}`); throw e; }