coulomb-social/scripts/test-attachments-browser.mjs
tegwick d9da608e65 Add private author-managed attachments with retained revisions
Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a192e9-c28b-7533-bf25-e2341364c22a
2026-10-31 19:38:10 +01:00

94 lines
4.9 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() {
const pending = page.waitForEvent('download');
await page.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');
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();
}