coulomb-social/scripts/test-copy-content.mjs
tegwick d521ddcbed
Some checks failed
Use-case regression gate / usecase-regressions (push) Has been cancelled
Preserve full Bubble protocol clipboard format
Assistant: codex
Assistant-Model: gpt-6.1-sol
Assistant-Session: 01a10e2d-a5ef-7e92-b03d-b1694e915680
2026-10-07 00:26:18 +02:00

82 lines
4.3 KiB
JavaScript

// Browser acceptance with synthetic content and intercepted clipboard writes.
import assert from 'node:assert/strict';
import { fileURLToPath } from 'node:url';
import { chromium } from 'playwright';
const browser = await chromium.launch({headless: true});
try {
const page = await browser.newPage();
const script = fileURLToPath(new URL('../coulomb_social/apps/spaces/static/spaces/copy-content.js', import.meta.url));
const expected = "Synthetic protocol\n\n*Synthetic board call*\n\n## Weekly call\n\n- Open point\n - Nested follow-up\n- Completed point\n\n### Protocol\n\nNew notes with **emphasis**.\n\nxxx";
const exportedHtml = '<p>Synthetic protocol</p><p><em>Synthetic board call</em></p><h2>Weekly call</h2><ul><li>Open point<ul><li>Nested follow-up</li></ul></li><li>Completed point</li></ul><h3>Protocol</h3><p>New notes with <strong>emphasis</strong>.</p><p>xxx</p>';
const fixture = `<nav>PRIVATE APP CHROME</nav>
<button id="copy-page-content">Copy content to clipboard</button>
<p id="copy-content-status" role="status"></p>
<textarea id="copy-content-manual" hidden></textarea>
<script type="application/json" id="page-clipboard-text">${JSON.stringify(expected)}</script>
<script type="application/json" id="page-clipboard-html">${JSON.stringify(exportedHtml)}</script>
<div id="page-content"><h1>Weekly call</h1><ul><li>Open point<ul><li>Nested follow-up</li></ul></li><li>Completed point</li></ul><h2>Protocol</h2><p>New notes with <strong>emphasis</strong>.</p></div>`;
// A secure origin enables the browser's native ClipboardItem implementation.
await page.route('https://clipboard.test/', route => route.fulfill({
contentType: 'text/html', body: fixture,
}));
await page.goto('https://clipboard.test/');
async function setup(mode) {
await page.setContent(fixture);
await page.evaluate(mode => {
window.receipts = [];
window.clipboardMode = mode;
Object.defineProperty(navigator, 'clipboard', {configurable: true, value: {
write: async items => {
if (window.clipboardMode !== 'rich') throw new Error('Rich clipboard denied');
const item = items[0];
window.receipts.push({html: await (await item.getType('text/html')).text(),
text: await (await item.getType('text/plain')).text()});
},
writeText: async text => {
if (window.clipboardMode === 'denied') throw new Error('Clipboard denied');
window.receipts.push({text});
},
}});
}, mode);
await page.addScriptTag({path: script});
}
for (const mode of ['rich', 'plain', 'denied']) {
await setup(mode);
await page.locator('#copy-page-content').click();
await page.waitForFunction(() => !document.getElementById('copy-page-content').disabled);
const result = await page.evaluate(() => ({
receipts: window.receipts,
status: document.getElementById('copy-content-status').textContent,
manual: document.getElementById('copy-content-manual').value,
hidden: document.getElementById('copy-content-manual').hidden,
selected: document.getElementById('copy-content-manual').selectionEnd,
}));
const text = mode === 'denied' ? result.manual : result.receipts[0].text;
assert.equal(text, expected);
assert.match(text, /Weekly call/);
assert.match(text, /- Open point/);
assert.match(text, / - Nested follow-up/);
assert.match(text, /- Completed point/);
assert.match(text, /New notes with \*\*emphasis\*\*/);
assert.doesNotMatch(text, /PRIVATE APP CHROME|Copy content to clipboard/);
if (mode === 'denied') {
assert.equal(result.receipts.length, 0);
assert.equal(result.hidden, false);
assert.equal(result.selected, result.manual.length);
assert.match(result.status, /Ctrl\+C or Cmd\+C/);
assert.doesNotMatch(result.status, /Content copied/);
} else {
assert.equal(result.receipts.length, 1);
assert.match(result.status, /Content copied/);
if (mode === 'rich') {
assert.match(result.receipts[0].html, /<ul><li>Open point/);
assert.match(result.receipts[0].html, /<strong>emphasis<\/strong>/);
assert.doesNotMatch(result.receipts[0].html, /PRIVATE APP CHROME/);
}
}
}
console.log('Clipboard browser checks passed: rich HTML, plain text, blocked/manual fallback.');
} finally {
await browser.close();
}