coulomb-social/scripts/test-attachments-browser.mjs
tegwick 31eaa581a6 Show saved attachments in editor and after stale edits
Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a192e9-c28b-7533-bf25-e2341364c22a
2026-10-31 21:52:23 +01:00

123 lines
6.7 KiB
JavaScript

import assert from 'node:assert/strict';
import {chromium} from 'playwright';
const base = new URL(process.argv[2]);
assert.equal(base.protocol, 'http:');
assert.ok(['localhost', '127.0.0.1'].includes(base.hostname));
const browser = await chromium.launch({headless: true});
try {
const context = await browser.newContext();
const unexpected = [];
await context.route('**/*', route => {
if (new URL(route.request().url()).origin === base.origin) return route.continue();
unexpected.push(route.request().url());
return route.abort();
});
const page = await context.newPage();
page.setDefaultTimeout(10000);
async function login(subject) {
await page.goto(`${base.origin}/auth/dev-login/`);
await page.getByLabel('Subject').fill(subject);
await page.getByLabel('Tenant').fill('tenant:attachment-test');
await page.getByRole('button', {name: 'Establish session'}).click();
await page.waitForURL('**/app/');
}
const shared = `${base.origin}/app/spaces/attachments-shared/`;
const destination = `${base.origin}/app/spaces/attachments-private/`;
const source = `${shared}?page=notes`;
async function menu(url, author) {
await page.goto(url);
await page.locator('summary', {hasText: 'Attachments'}).click();
await page.getByRole('link', {name: author
? 'Open, download or manage attachments' : 'Open or download attachments', exact: true}).click();
await page.waitForURL('**/attachments/');
}
async function downloadedBytes(tab = page) {
const pending = tab.waitForEvent('download');
await tab.getByRole('link', {name: 'Download', exact: true}).click();
const stream = await (await pending).createReadStream();
const chunks = [];
for await (const chunk of stream) chunks.push(chunk);
return Buffer.concat(chunks).toString();
}
await login('file-author');
await menu(source, true);
await page.getByLabel('File (up to 16 MiB)').setInputFiles({
name: 'meeting-notes.txt', mimeType: 'text/plain', buffer: Buffer.from('Synthetic attachment bytes'),
});
await page.getByRole('button', {name: 'Add attachment', exact: true}).click();
await page.waitForURL('**/attachments/');
assert.match(await page.locator('main').innerText(), /Attachment added/);
const originalDownload = await page.getByRole('link', {name: 'Download', exact: true}).getAttribute('href');
assert.equal(await downloadedBytes(), 'Synthetic attachment bytes');
const editUrl = `${shared}pages/notes/edit/`;
await page.goto(editUrl);
const files = page.getByRole('region', {name: 'Attachments', exact: true});
assert.match(await files.innerText(), /meeting-notes.txt/);
assert.equal(await downloadedBytes(), 'Synthetic attachment bytes');
await page.getByLabel('Body (markdown)').fill('Unsaved author notes');
const opened = context.waitForEvent('page');
await page.getByRole('link', {name: 'Manage attachments (new tab)', exact: true}).click();
const management = await opened;
await management.waitForURL('**/attachments/');
assert.equal(await page.getByLabel('Body (markdown)').inputValue(), 'Unsaved author notes');
assert.match(await management.locator('main').innerText(), /meeting-notes.txt/);
await management.close();
const stale = await context.newPage();
await stale.goto(editUrl);
assert.match(await stale.getByRole('region', {name: 'Attachments', exact: true}).innerText(), /meeting-notes.txt/);
await stale.getByLabel('Body (markdown)').fill('Keep my stale edit');
await page.getByRole('button', {name: 'Save page', exact: true}).click();
await page.waitForURL('**?page=notes');
await stale.getByRole('button', {name: 'Save page', exact: true}).click();
await stale.waitForURL('**/edit/');
assert.match(await stale.locator('main').innerText(), /This page changed/);
assert.equal(await stale.getByLabel('Body (markdown)').inputValue(), 'Keep my stale edit');
assert.match(await stale.getByRole('region', {name: 'Attachments', exact: true}).innerText(), /meeting-notes.txt/);
assert.equal(await downloadedBytes(stale), 'Synthetic attachment bytes');
await stale.close();
await page.goto(editUrl);
assert.equal(await page.getByLabel('Body (markdown)').inputValue(), 'Unsaved author notes\n');
assert.match(await files.innerText(), /meeting-notes.txt/);
await login('file-reader');
await menu(source, false);
assert.equal(await page.getByRole('button', {name: 'Add attachment', exact: true}).count(), 0);
assert.equal(await page.getByRole('button', {name: 'Remove from page', exact: true}).count(), 0);
assert.equal(await downloadedBytes(), 'Synthetic attachment bytes');
await login('file-outsider');
assert.equal((await page.goto(new URL(originalDownload, base).href)).status(), 404);
assert.equal((await page.goto(`${shared}pages/notes/attachments/`)).status(), 404);
await login('file-author');
await page.goto(source);
await page.getByRole('link', {name: 'Duplicate page', exact: true}).click();
await page.getByLabel('Destination space').selectOption('attachments-private');
await page.getByLabel('Title', {exact: false}).fill('Independent files');
await page.getByLabel('New page slug', {exact: false}).fill('copied');
await page.getByRole('button', {name: 'Create duplicate'}).click();
await page.waitForURL('**?page=copied');
await menu(`${destination}?page=copied`, true);
assert.equal(await downloadedBytes(), 'Synthetic attachment bytes');
const copiedDownload = await page.getByRole('link', {name: 'Download', exact: true}).getAttribute('href');
assert.notEqual(copiedDownload, originalDownload);
await page.getByRole('button', {name: 'Remove from page', exact: true}).click();
await page.waitForURL('**/attachments/');
assert.match(await page.locator('main').innerText(), /No attachments on this page/);
await menu(source, true);
assert.equal(await downloadedBytes(), 'Synthetic attachment bytes');
await page.goto(source);
await page.getByRole('link', {name: 'Transfer', exact: true}).click();
await page.getByLabel('Destination space').selectOption('attachments-private');
await page.getByLabel('Slug in destination', {exact: false}).fill('moved');
await page.getByRole('button', {name: 'Transfer page', exact: true}).click();
await page.waitForURL('**?page=moved');
await menu(`${destination}?page=moved`, true);
assert.equal(await downloadedBytes(), 'Synthetic attachment bytes');
const movedDownload = await page.getByRole('link', {name: 'Download', exact: true}).getAttribute('href');
await login('file-reader');
assert.equal((await page.goto(source)).status(), 404);
assert.equal((await page.goto(new URL(movedDownload, base).href)).status(), 404);
assert.deepEqual(unexpected, []);
console.log('Attachment menu upload, download, independent copy, move and removal passed');
} finally {
await browser.close();
}