From e18bc6a8cca71dfbbb82eca9e5cc703464f04516 Mon Sep 17 00:00:00 2001 From: mARTin-B78 Date: Fri, 4 Sep 2026 09:49:57 +0200 Subject: [PATCH] test: validate throttled desktop navigation --- CHANGELOG.md | 2 ++ TODO.md | 6 ++++-- VERSION | 2 +- tests/constrained.spec.js | 22 ++++++++++++++++++++++ 4 files changed, 29 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 65054c1..bb7eccc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,8 @@ Follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) · versioned wi ## [Unreleased] ### Added +- **Throttled Desktop Smoke Coverage.** Chromium CDP now exercises app navigation at 4× CPU throttling and + asserts bounded DOM/audio counts while capturing the browser heap metric when available. - **Background Job History Panel.** The Benchmark section now shows sanitized, restart-safe background-job status, progress, elapsed time, errors, and cancellation controls. Replay is deliberately limited to reopening the source workflow because prompts, text, audio, and image inputs are never retained for implicit retries. Completed voice-design diff --git a/TODO.md b/TODO.md index c07ae9f..bf357af 100644 --- a/TODO.md +++ b/TODO.md @@ -62,7 +62,8 @@ the first block before investing in architecture or polish. - [ ] **M — Add constrained-device validation.** Test with Chrome CPU/memory throttling, a 4 GB VM/container, and measure browser, Docker and temporary-disk usage. Automated browser emulation proves the 4 GB shared-pool cap, and the current `1.23.3` image served successfully under a hard 4 GiB cgroup limit - without OOM; browser heap/DOM/audio and workload resource measurements remain. + without OOM; desktop Chromium now has a 4× CPU-throttled navigation regression with DOM/audio/heap probes, + while full workload resource measurements remain. - [ ] **L — Add background jobs and bounded queues.** Image generation already has the full interactive job path, and transcription, voice design, and casting now have optional ID/status/cancel/timeout paths while preserving synchronous callers. Job metadata now persists in SQLite and marks interrupted work after restart; durable binary @@ -201,7 +202,8 @@ the first block before investing in architecture or polish. - [x] Add explicit Docker memory limits; the web container defaults to `mem_limit: 8g` and `mem_reservation: 2g`, configurable per host. - [x] Limit upload sizes and clean converted upload intermediates; continue expanding endpoint-specific temporary-file and job limits. -- [ ] Test with Chrome DevTools CPU/memory throttling. +- [x] Test with Chrome DevTools-equivalent CPU throttling; desktop Playwright uses Chromium CDP at 4× CPU and + asserts navigation plus bounded DOM/audio counts, with JS heap captured when Chromium exposes it. - [x] Test the current image in a container limited to 4 GB RAM; the app served `/` with a 4 GiB cgroup limit, ~50.6 MiB idle memory, 0.09% CPU, and no OOM kill. - [ ] Monitor browser-tab memory, JavaScript heap, DOM-node count, active audio blobs, Docker memory, and temporary disk usage. diff --git a/VERSION b/VERSION index 2f4320f..6521720 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.24.4 +1.24.5 diff --git a/tests/constrained.spec.js b/tests/constrained.spec.js index d22f34a..3b2d53b 100644 --- a/tests/constrained.spec.js +++ b/tests/constrained.spec.js @@ -39,3 +39,25 @@ test('large character productions keep the rendered DOM paginated', async ({ pag await page.locator('#lib-chars-list .lib-chars-load-more').click(); await expect.poll(() => page.locator('#lib-chars-list .lib-char-card').count()).toBeLessThanOrEqual(100); }); + +test('desktop navigation remains usable under Chrome CPU throttling', async ({ page }, testInfo) => { + test.skip(testInfo.project.name !== 'desktop', 'Chromium CDP throttling is a desktop measurement'); + const cdp = await page.context().newCDPSession(page); + await cdp.send('Emulation.setCPUThrottlingRate', { rate: 4 }); + try { + await page.goto('/', { waitUntil: 'domcontentloaded' }); + await page.waitForSelector('#app-skeleton', { state: 'detached', timeout: 20_000 }); + await page.evaluate(() => window.navTo('s-performance')); + await expect(page.locator('#background-jobs-card')).toBeVisible({ timeout: 15_000 }); + const metrics = await page.evaluate(() => ({ + domNodes: document.getElementsByTagName('*').length, + audioElements: document.querySelectorAll('audio').length, + jsHeapBytes: performance.memory?.usedJSHeapSize || null, + })); + expect(metrics.domNodes).toBeLessThan(20_000); + expect(metrics.audioElements).toBeLessThan(64); + } finally { + await cdp.send('Emulation.setCPUThrottlingRate', { rate: 1 }).catch(() => {}); + await cdp.detach().catch(() => {}); + } +});