mirror of
https://github.com/pewdiepie-archdaemon/odysseus.git
synced 2026-09-14 12:12:20 +02:00
103 lines
4.7 KiB
Python
103 lines
4.7 KiB
Python
"""Browser regression coverage for document autosave state and ordering."""
|
|
|
|
import json
|
|
import subprocess
|
|
from pathlib import Path
|
|
|
|
|
|
ROOT = Path(__file__).resolve().parents[1]
|
|
|
|
|
|
def test_save_status_is_dirty_race_safe_and_reports_failures():
|
|
script = r"""
|
|
import { chromium } from 'playwright';
|
|
const browser = await chromium.launch({ headless: true });
|
|
const page = await browser.newPage({ viewport: { width: 900, height: 700 } });
|
|
const bodies = [];
|
|
let active = 0;
|
|
let maxActive = 0;
|
|
let requests = 0;
|
|
await page.route('**/api/document/status-doc', async route => {
|
|
requests += 1;
|
|
active += 1;
|
|
maxActive = Math.max(maxActive, active);
|
|
bodies.push(route.request().postDataJSON().content);
|
|
if (requests === 1) await new Promise(resolve => setTimeout(resolve, 120));
|
|
const fail = requests === 3;
|
|
await route.fulfill({
|
|
status: fail ? 500 : 200,
|
|
contentType: 'application/json',
|
|
body: JSON.stringify(fail ? { error: 'failed' } : { version_count: 1 }),
|
|
});
|
|
active -= 1;
|
|
});
|
|
await page.goto('http://127.0.0.1:7011/static/js/documentStats.js');
|
|
await page.setContent('<link rel="stylesheet" href="/static/style.css?v=20260831richtexttools91"><div id="toast"></div><div id="chat-container"></div><div id="sidebar"></div>');
|
|
await page.evaluate(async () => {
|
|
const mod = await import('/static/js/document.js?v=20260831richtexttools91&save-status-test=1');
|
|
mod.init('/api');
|
|
mod.injectFreshDoc({ id: 'status-doc', title: 'Status', language: 'markdown', current_content: 'initial', version_count: 1 });
|
|
await new Promise(resolve => setTimeout(resolve, 180));
|
|
window.__documentModuleForTest = mod;
|
|
});
|
|
|
|
const initial = await page.locator('#doc-footer-copy-btn').getAttribute('data-save-state');
|
|
await page.evaluate(() => {
|
|
const textarea = document.querySelector('#doc-editor-textarea');
|
|
textarea.value = 'first edit';
|
|
textarea.dispatchEvent(new Event('input', { bubbles: true }));
|
|
});
|
|
const dirty = await page.locator('#doc-footer-copy-btn').getAttribute('data-save-state');
|
|
await page.evaluate(() => {
|
|
const textarea = document.querySelector('#doc-editor-textarea');
|
|
window.__saveOne = window.__documentModuleForTest.saveDocument({ silent: true });
|
|
textarea.value = 'newer edit';
|
|
textarea.dispatchEvent(new Event('input', { bubbles: true }));
|
|
window.__saveTwo = window.__documentModuleForTest.saveDocument({ silent: true });
|
|
});
|
|
await page.waitForTimeout(35);
|
|
const duringSave = await page.locator('#doc-footer-copy-btn').getAttribute('data-save-state');
|
|
await page.evaluate(() => Promise.all([window.__saveOne, window.__saveTwo]));
|
|
const afterSave = await page.locator('#doc-footer-copy-btn').getAttribute('data-save-state');
|
|
|
|
await page.evaluate(async () => {
|
|
const textarea = document.querySelector('#doc-editor-textarea');
|
|
textarea.value = 'failing edit';
|
|
textarea.dispatchEvent(new Event('input', { bubbles: true }));
|
|
await window.__documentModuleForTest.saveDocument({ silent: true });
|
|
});
|
|
const afterFailure = await page.locator('#doc-footer-copy-btn').getAttribute('data-save-state');
|
|
const footer = await page.locator('#doc-actions-footer').evaluate(el => ({
|
|
clientWidth: el.clientWidth,
|
|
scrollWidth: el.scrollWidth,
|
|
}));
|
|
await page.setViewportSize({ width: 390, height: 844 });
|
|
await page.waitForTimeout(50);
|
|
const mobile = await page.locator('#doc-actions-footer').evaluate(el => ({
|
|
clientWidth: el.clientWidth,
|
|
scrollWidth: el.scrollWidth,
|
|
labelDisplay: getComputedStyle(document.querySelector('.doc-save-button-label')).display,
|
|
}));
|
|
console.log(JSON.stringify({ initial, dirty, duringSave, afterSave, afterFailure, bodies, maxActive, footer, mobile }));
|
|
await browser.close();
|
|
"""
|
|
result = subprocess.run(
|
|
["node", "--input-type=module", "-e", script],
|
|
cwd=ROOT,
|
|
check=False,
|
|
capture_output=True,
|
|
text=True,
|
|
)
|
|
assert result.returncode == 0, result.stderr
|
|
data = json.loads(result.stdout)
|
|
assert data["initial"] == "saved"
|
|
assert data["dirty"] == "dirty"
|
|
assert data["duringSave"] == "saving"
|
|
assert data["afterSave"] == "saved"
|
|
assert data["afterFailure"] == "error"
|
|
assert data["bodies"] == ["first edit", "newer edit", "failing edit"]
|
|
assert data["maxActive"] == 1
|
|
assert data["footer"]["scrollWidth"] <= data["footer"]["clientWidth"]
|
|
assert data["mobile"]["scrollWidth"] <= data["mobile"]["clientWidth"]
|
|
assert data["mobile"]["labelDisplay"] == "none"
|