// @ts-check import { test, expect } from '@playwright/test'; import { loadTestUser } from '../utils/testUser.js'; test.describe('@p0 Support — submit ticket', () => { test.setTimeout(15000); test('open → fill form → submit → success (network or UI)', async ({ page }) => { const user = loadTestUser(); const stamp = new Date().toISOString().replace(/[-:TZ.]/g, ''); // Sign in await page.context().clearCookies(); await page.goto('/signin', { waitUntil: 'networkidle' }); await page.getByPlaceholder('Username', { exact: true }).fill(user.username); await page.getByPlaceholder('Password', { exact: true }).fill(user.password); await page.getByRole('button', { name: /^Sign In$/ }).click(); await page.waitForURL('**/signin-landing**', { timeout: 15000 }); // Open Support const supportBtn = page.getByRole('button', { name: /^Support$/i }).or(page.getByText(/^Support$/i)); await supportBtn.click(); const overlay = page.locator('div.fixed.inset-0').first(); await expect(overlay).toBeVisible({ timeout: 5000 }); const dlg = overlay.locator('div[role="dialog"], div.bg-white').first(); // Fill Subject/Message (tolerant selectors) const subj = dlg.getByLabel(/Subject/i) .or(dlg.getByPlaceholder(/Subject/i)) .or(dlg.locator('input[type="text"]')) .first(); const msg = dlg.getByLabel(/(Message|Describe|How can we help)/i) .or(dlg.locator('textarea')) .first(); await subj.fill(`E2E support ${stamp}`); await msg.fill(`Automated E2E support test at ${stamp}. Please ignore. User=${user.username}`); // Submit button const send = dlg.getByRole('button', { name: /(Send|Submit|Send message|Submit ticket|Send request)/i }).first(); await expect(send).toBeEnabled({ timeout: 5000 }); // Start the response wait **before** clicking const respPromise = page.waitForResponse(r => r.request().method() === 'POST' && /\/api\/support$/.test(r.url()), { timeout: 15000 } ).catch(() => null); await send.click(); // Consider success if we saw a POST with a reasonable status const resp = await respPromise; const okStatus = resp ? [200, 201, 202, 204, 409, 429].includes(resp.status()) : false; // Also allow UI signals const successText = page.getByText(/(thanks|we'll get back|message sent|received)/i).first(); const successShown = await successText.isVisible({ timeout: 3000 }).catch(() => false); // Close the overlay (cover multiple close mechanisms) const closeByText = dlg.getByRole('button', { name: /(Close|Done|OK|Cancel|Dismiss)/i }).first(); const closeByAria = dlg.locator('[aria-label="Close"], [aria-label="close"]').first(); if (await closeByText.isVisible({ timeout: 500 }).catch(() => false)) { await closeByText.click(); } else if (await closeByAria.isVisible({ timeout: 200 }).catch(() => false)) { await closeByAria.click(); } else { await page.keyboard.press('Escape'); } const overlayHidden = await overlay.isHidden({ timeout: 8000 }).catch(() => false); expect(okStatus || successShown || overlayHidden).toBeTruthy(); }); });