Files

68 lines
3.9 KiB
JavaScript

// Packaged wizard proof only: synthetic signer, no relay/payment/native claims.
import { chromium, expect } from '@playwright/test';
import { createRequire } from 'node:module';
import { createHash } from 'node:crypto';
import assert from 'node:assert/strict';
const { finalizeEvent, getPublicKey } = createRequire('/signer/package.json')('nostr-tools/pure');
const base = 'http://127.0.0.1:8095';
const blob = 'http://127.0.0.1:3000';
const bytes = Buffer.alloc(17 * 1024 * 1024, 37);
const hash = createHash('sha256').update(bytes).digest('hex');
const secret = new Uint8Array(32).fill(1);
const browser = await chromium.launch({ executablePath: process.env.CHROMIUM_EXECUTABLE,
headless: true, args: ['--no-sandbox', '--disable-dev-shm-usage'] });
try {
const context = await browser.newContext({ serviceWorkers: 'block', viewport: { width: 390, height: 844 } });
await context.route('**/*', route => [base, blob].includes(new URL(route.request().url()).origin) ? route.continue() : route.abort());
await context.routeWebSocket('**/*', socket => socket.close());
let logins = 0, uploads = 0;
await context.exposeFunction('fixtureSign', event => {
if (event.kind === 27235) {
assert.ok(event.tags.some(t => t[0] === 'u' && t[1] === base+'/api/auth/login'));
assert.ok(event.tags.some(t => t[0] === 'method' && t[1] === 'POST'));
logins++;
} else {
assert.equal(event.kind, 24242);
assert.ok(event.tags.some(t => t[0] === 't' && t[1] === 'upload'));
assert.ok(event.tags.some(t => t[0] === 'x' && t[1] === hash));
uploads++;
}
return finalizeEvent(event, secret); // Do not inject missing production tags.
});
await context.addInitScript(pubkey => {
window.__archipelagoNostr = true;
window.nostr = { getPublicKey: async () => pubkey, signEvent: event => window.fixtureSign(event) };
}, getPublicKey(secret));
const page = await context.newPage();
const errors = [];
page.on('pageerror', e => errors.push(e.message));
await page.goto(base+'/login');
await page.getByRole('button', { name: 'Log in with nostr', exact: true }).click();
await page.waitForURL(base+'/');
const created = await context.request.post(base+'/api/podcasts', { headers: { origin: base }, data: { title: 'Synthetic large upload qualification' } });
assert.equal(created.status(), 201, await created.text());
const podcast = await created.json();
await page.goto(base+'/upload');
await page.getByRole('button', { name: 'Synthetic large upload qualification', exact: true }).click();
await page.locator('input[type=file]').setInputFiles({ name: 'synthetic-17MiB.mp4', mimeType: 'video/mp4', buffer: bytes });
await page.getByLabel('Episode title', { exact: true }).fill('Synthetic large episode');
const result = page.waitForResponse(r => r.url() === blob+'/upload' && r.request().method() === 'PUT', { timeout: 45000 });
await page.getByRole('button', { name: 'Upload & publish', exact: true }).click();
const response = await result;
assert.equal(response.status(), 201, await response.text());
await expect(page.getByRole('heading', { name: '🎉 Episode published!', exact: true })).toBeVisible();
await page.reload();
const stored = await context.request.get(base+'/api/podcasts/'+podcast.id);
assert.equal(stored.status(), 200);
const data = await stored.json();
assert.equal(data.episodes.length, 1);
assert.equal(data.episodes[0].title, 'Synthetic large episode');
assert.equal(data.episodes[0].price_sats, null);
assert.equal(data.episodes[0].enclosure_url, blob+'/'+hash+'.mp4');
const download = await context.request.get(data.episodes[0].enclosure_url);
assert.equal(download.status(), 200);
assert.deepEqual(await download.body(), bytes);
assert.equal(logins, 1); assert.equal(uploads, 1); assert.deepEqual(errors, []);
console.log('PASS packaged wizard17MiB upload→free episode→reload→exact bytes; synthetic signer, not native/manager acceptance');
} finally { await browser.close(); }