71 lines
4.4 KiB
JavaScript
71 lines
4.4 KiB
JavaScript
// Actual packaged dashboard and API. Only signer is synthetic; never native UAT.
|
|
import { chromium, expect } from '@playwright/test';
|
|
import { createRequire } from 'node:module';
|
|
// Reuse the exact Podsteadr image's public dependency bytes, not a new npm install.
|
|
const { finalizeEvent, getPublicKey } = createRequire('/signer/package.json')('nostr-tools/pure');
|
|
import assert from 'node:assert/strict';
|
|
const base = 'http://127.0.0.1:8095';
|
|
const allowed = new Set([base, 'http://127.0.0.1:3000', 'http://127.0.0.1:8888']);
|
|
const secret = new Uint8Array(32).fill(1);
|
|
let signatures = 0;
|
|
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 => allowed.has(new URL(route.request().url()).origin) ? route.continue() : route.abort());
|
|
await context.routeWebSocket('**/*', socket => socket.close());
|
|
await context.exposeFunction('fixtureSign', event => {
|
|
assert.equal(event.kind, 27235, 'Fixture must never sign a publication/payment');
|
|
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'));
|
|
signatures++;
|
|
return finalizeEvent(event, secret);
|
|
});
|
|
await context.addInitScript(pubkey => {
|
|
// This scenario substitutes only the signer, explicitly. Canonical bridge
|
|
// bytes/inclusion are checked separately; no native-broker credit is claimed.
|
|
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', error => errors.push(error.message));
|
|
await page.goto(base+'/login');
|
|
assert.equal(await page.locator('script[src="/nostr-provider.js"][data-app-id="podsteadr"][data-no-nip98]').count(), 1);
|
|
await page.getByRole('button', { name: 'Log in with nostr', exact: true }).click();
|
|
await page.waitForURL(base+'/');
|
|
assert.equal(signatures, 1);
|
|
const streams = await (await context.request.get(base+'/api/streams')).json();
|
|
assert.equal(streams.length, 1);
|
|
const stream = streams[0];
|
|
await page.goto(base+'/streams/'+stream.id);
|
|
await expect(page.getByRole('heading', { name: stream.title, exact: true })).toBeVisible();
|
|
await expect(page.getByRole('heading', { name: 'Recordings', exact: true })).toBeVisible();
|
|
const target = page.getByLabel('Publish to podcast', { exact: true });
|
|
await target.selectOption({ label: 'Synthetic recording qualification' });
|
|
const podcastId = await target.inputValue();
|
|
const pending = page.waitForResponse(r => r.url() === base+'/api/streams/'+stream.id+'/recordings/publish' && r.request().method() === 'POST');
|
|
await page.getByRole('button', { name: 'Publish as episode', exact: true }).first().click();
|
|
const response = await pending;
|
|
assert.equal(response.status(), 201);
|
|
const episode = await response.json();
|
|
assert.equal(episode.price_sats, null);
|
|
await expect(page.getByText('Published! Feed:', { exact: false })).toBeVisible();
|
|
const feed = page.getByRole('link', { name: base+'/feeds/'+podcastId+'/feed.xml', exact: true });
|
|
await expect(feed).toBeVisible();
|
|
assert.equal((await context.request.get(episode.enclosure_url)).status(), 200);
|
|
for (const width of [390, 1440]) {
|
|
await page.setViewportSize({ width, height: 900 });
|
|
await page.reload();
|
|
await expect(page.getByRole('heading', { name: 'Recordings', exact: true })).toBeVisible();
|
|
assert.equal(await page.evaluate(() => document.documentElement.scrollWidth > innerWidth+1), false, `horizontal overflow at ${width}px`);
|
|
}
|
|
const podcast = await (await context.request.get(base+'/api/podcasts/'+podcastId)).json();
|
|
assert.equal(podcast.episodes.length, 2);
|
|
assert.ok(podcast.episodes.some(e => e.id === episode.id));
|
|
assert.equal(signatures, 1, 'Reload should retain the actual cookie session');
|
|
assert.deepEqual(errors, []);
|
|
await context.close();
|
|
console.log('PASS actual packaged dashboard synthetic-signer login→recording selection→free episode publication→feed, mobile/desktop reload, real cookie persistence; no native-identity/physical acceptance');
|
|
} finally { await browser.close(); }
|