const { chromium } = require('@playwright/test'); const fs = require('fs'); const path = require('path'); const BASE_URL = process.env.PLAYWRIGHT_BASE_URL || 'http://127.0.0.1:4132'; const ARTIFACTS_DIR = path.join(__dirname, 'artifacts', 'status-flow'); const LOGIN_USERNAME = 'toemrer'; const LOGIN_PASSWORD = process.env.AUTH_PASSWORD; async function ensureArtifactsDir() { fs.mkdirSync(ARTIFACTS_DIR, { recursive: true }); } async function login(page) { await page.goto(BASE_URL, { waitUntil: 'networkidle', timeout: 30000 }); const onLogin = await page.getByRole('heading', { name: /Log ind/i }).isVisible({ timeout: 5000 }).catch(() => false); if (!onLogin) { return; } await page.locator('input[type="text"]').first().fill(LOGIN_USERNAME); await page.locator('input[type="password"]').first().fill(LOGIN_PASSWORD); await page.getByRole('button', { name: /Log ind/i }).click(); await page.waitForLoadState('networkidle', { timeout: 20000 }).catch(() => {}); await page.waitForTimeout(1500); } async function getProjectSnapshot(page, projectName) { return await page.evaluate(async ({ projectName }) => { const token = localStorage.getItem('accessToken'); const response = await fetch('/api/customer-projects/projects', { headers: token ? { Authorization: `Bearer ${token}` } : {} }); const data = await response.json(); const project = (data.projects || []).find((item) => item.project_name === projectName); return project ? { id: project.id, status: project.project_status, customer_name: project.customer_name } : null; }, { projectName }); } async function waitForProjectSnapshot(page, projectName, maxAttempts = 10) { for (let attempt = 0; attempt < maxAttempts; attempt += 1) { const snapshot = await getProjectSnapshot(page, projectName); if (snapshot) { return snapshot; } await page.waitForTimeout(1000); } return null; } async function fillGeometry(page) { const widthInput = page.locator('input[placeholder="10"]').first(); const lengthInput = page.locator('input[placeholder="15"]').first(); await widthInput.waitFor({ state: 'visible', timeout: 10000 }); await widthInput.fill('10'); await lengthInput.fill('12'); const saveBtn = page.getByRole('button', { name: /Gem Nu|Gem Geometri/i }).first(); await saveBtn.click(); await page.waitForTimeout(6000); } async function completeSmartPackage(page) { const continueBtn = page.getByRole('button', { name: /Fortsæt til Smart Pakke/i }).first(); if (await continueBtn.isVisible({ timeout: 5000 }).catch(() => false)) { await continueBtn.click(); } else { await page.locator('.step').filter({ hasText: /Smart Pakke/i }).first().click(); } await page.waitForTimeout(3000); const packageOptions = page.locator('.package-option'); const packageCount = await packageOptions.count(); if (packageCount === 0) { throw new Error('Ingen smart pakker fundet i UI'); } await packageOptions.first().click(); await page.waitForTimeout(2500); const saveSmartPackageBtn = page.getByRole('button', { name: /Gem Smart Pakke/i }).first(); if (await saveSmartPackageBtn.isVisible({ timeout: 5000 }).catch(() => false)) { await saveSmartPackageBtn.click(); await page.waitForTimeout(1500); } } async function goToFinalReview(page) { const nextBtn = page.getByRole('button', { name: /Næste.*Final Review/i }).first(); if (await nextBtn.isVisible({ timeout: 5000 }).catch(() => false)) { await nextBtn.click(); } else { await page.locator('.step').filter({ hasText: /Final Review/i }).first().click(); } await page.waitForTimeout(5000); } async function main() { await ensureArtifactsDir(); const browser = await chromium.launch({ headless: true }); const page = await browser.newPage({ viewport: { width: 1440, height: 1400 } }); const projectName = `Status Flow ${Date.now()}`; try { await login(page); console.log('STEP login', JSON.stringify({ url: page.url() })); const newProjectBtn = page.getByRole('button', { name: /Nyt Projekt/i }); if (await newProjectBtn.isVisible({ timeout: 10000 }).catch(() => false)) { await newProjectBtn.click(); await page.waitForTimeout(500); } await page.locator('#field-projectName').fill(projectName); await page.locator('#field-customerName').fill('Status Flow Testkunde'); await page.locator('#field-customerEmail').fill('statusflow@example.com'); await page.locator('#field-projectDescription').fill('Test af persisted statusflow for tømrer med tagmål og smart pakke.'); await page.getByRole('button', { name: /Gem Projekt/i }).click(); await page.waitForTimeout(4000); await page.screenshot({ path: path.join(ARTIFACTS_DIR, '01-after-create.png'), fullPage: true }); let snapshot = await waitForProjectSnapshot(page, projectName); console.log('STEP after_create', JSON.stringify(snapshot)); await fillGeometry(page); await page.screenshot({ path: path.join(ARTIFACTS_DIR, '02-after-geometry.png'), fullPage: true }); snapshot = await waitForProjectSnapshot(page, projectName); console.log('STEP after_geometry', JSON.stringify(snapshot)); await completeSmartPackage(page); await page.screenshot({ path: path.join(ARTIFACTS_DIR, '03-after-smart-package.png'), fullPage: true }); snapshot = await waitForProjectSnapshot(page, projectName); console.log('STEP after_smart_package', JSON.stringify(snapshot)); await goToFinalReview(page); await page.screenshot({ path: path.join(ARTIFACTS_DIR, '04-final-review.png'), fullPage: true }); snapshot = await waitForProjectSnapshot(page, projectName); console.log('STEP after_review', JSON.stringify({ snapshot, hasReadyButton: await page.getByRole('button', { name: /Klar til Ordrestyring/i }).isVisible().catch(() => false), hasSendButton: await page.getByRole('button', { name: /Send til Ordrestyring/i }).isVisible().catch(() => false) })); const readyBtn = page.getByRole('button', { name: /Klar til Ordrestyring/i }).first(); if (await readyBtn.isVisible({ timeout: 5000 }).catch(() => false)) { await readyBtn.click(); await page.waitForTimeout(3000); } await page.screenshot({ path: path.join(ARTIFACTS_DIR, '05-after-ready.png'), fullPage: true }); snapshot = await waitForProjectSnapshot(page, projectName); console.log('STEP after_ready', JSON.stringify(snapshot)); const sendBtn = page.getByRole('button', { name: /Send til Ordrestyring/i }).first(); let sendResult = 'button_not_found'; if (await sendBtn.isVisible({ timeout: 5000 }).catch(() => false)) { await sendBtn.click(); await page.waitForTimeout(15000); const bodyText = await page.locator('body').textContent(); if (bodyText.includes('Tilbud sendt til ordrestyring')) { sendResult = 'success'; } else if (bodyText.includes('Fejl ved indsendelse')) { sendResult = 'error'; } else { sendResult = 'unknown'; } } await page.screenshot({ path: path.join(ARTIFACTS_DIR, '06-after-send.png'), fullPage: true }); snapshot = await waitForProjectSnapshot(page, projectName); console.log('STEP after_send', JSON.stringify({ snapshot, sendResult })); } finally { await browser.close(); } } main().catch((error) => { console.error('STATUS_FLOW_ERROR', error); process.exit(1); });