chore: satisfy prettier in frontend and e2e
`checks.yml` runs `npm run format:check` for both projects and both were failing. - frontend/src/lib/ui-store.ts is mine, unformatted since the round-1 upload-queue badge fix — the same miss as the rustfmt one: I gated on svelte-check and eslint but never on format:check. - e2e/loadtest/* and e2e/shots.mjs have been unformatted since7758270and are unrelated to the audit work. Fixed here because they block the same gate and the fix is mechanical; no behaviour change in either project. Still red and deliberately NOT fixed here: `npm run lint` in the frontend reports `svelte/prefer-svelte-reactivity` on routes/diashow/+page.svelte:208 (a mutable `Set` where the rule wants `SvelteSet`), pre-existing since5009590. That one is a real reactivity change in code I have no test coverage for, so it belongs in its own change rather than smuggled into a formatting commit. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
140
e2e/shots.mjs
140
e2e/shots.mjs
@@ -4,24 +4,44 @@ import { chromium, devices } from '@playwright/test';
|
||||
import { Client } from 'pg';
|
||||
import { readFileSync, mkdirSync } from 'node:fs';
|
||||
|
||||
|
||||
const BASE = 'http://localhost:3101';
|
||||
const PHOTOS = '/tmp/eventsnap-shots/photos';
|
||||
const OUT = '/tmp/eventsnap-shots';
|
||||
mkdirSync(OUT, { recursive: true });
|
||||
|
||||
const api = (path, opts = {}) =>
|
||||
fetch(`${BASE}/api/v1${path}`, opts).then(async (r) => ({ status: r.status, body: await r.text().then((t) => { try { return JSON.parse(t); } catch { return t; } }) }));
|
||||
fetch(`${BASE}/api/v1${path}`, opts).then(async (r) => ({
|
||||
status: r.status,
|
||||
body: await r.text().then((t) => {
|
||||
try {
|
||||
return JSON.parse(t);
|
||||
} catch {
|
||||
return t;
|
||||
}
|
||||
}),
|
||||
}));
|
||||
|
||||
const authHeaders = (jwt, json = true) => ({ Authorization: `Bearer ${jwt}`, ...(json ? { 'Content-Type': 'application/json' } : {}) });
|
||||
const authHeaders = (jwt, json = true) => ({
|
||||
Authorization: `Bearer ${jwt}`,
|
||||
...(json ? { 'Content-Type': 'application/json' } : {}),
|
||||
});
|
||||
|
||||
async function adminLogin() {
|
||||
const r = await api('/admin/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ password: 'admin-test-pw' }) });
|
||||
const r = await api('/admin/login', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ password: 'admin-test-pw' }),
|
||||
});
|
||||
return r.body.jwt;
|
||||
}
|
||||
async function joinGuest(name) {
|
||||
const r = await api('/join', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ display_name: name }) });
|
||||
if (r.status !== 201) throw new Error('join failed ' + name + ' ' + r.status + ' ' + JSON.stringify(r.body));
|
||||
const r = await api('/join', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ display_name: name }),
|
||||
});
|
||||
if (r.status !== 201)
|
||||
throw new Error('join failed ' + name + ' ' + r.status + ' ' + JSON.stringify(r.body));
|
||||
return r.body; // {jwt,pin,user_id}
|
||||
}
|
||||
async function upload(jwt, file, caption, hashtags) {
|
||||
@@ -29,7 +49,11 @@ async function upload(jwt, file, caption, hashtags) {
|
||||
form.append('file', new Blob([readFileSync(file)], { type: 'image/jpeg' }), 'photo.jpg');
|
||||
if (caption) form.append('caption', caption);
|
||||
if (hashtags) form.append('hashtags', hashtags);
|
||||
const r = await fetch(`${BASE}/api/v1/upload`, { method: 'POST', headers: authHeaders(jwt, false), body: form });
|
||||
const r = await fetch(`${BASE}/api/v1/upload`, {
|
||||
method: 'POST',
|
||||
headers: authHeaders(jwt, false),
|
||||
body: form,
|
||||
});
|
||||
if (r.status !== 201) throw new Error('upload failed ' + r.status + ' ' + (await r.text()));
|
||||
return (await r.json()).id;
|
||||
}
|
||||
@@ -37,16 +61,34 @@ async function like(jwt, id) {
|
||||
await fetch(`${BASE}/api/v1/upload/${id}/like`, { method: 'POST', headers: authHeaders(jwt) });
|
||||
}
|
||||
async function comment(jwt, id, body) {
|
||||
await fetch(`${BASE}/api/v1/upload/${id}/comments`, { method: 'POST', headers: authHeaders(jwt), body: JSON.stringify({ body }) });
|
||||
await fetch(`${BASE}/api/v1/upload/${id}/comments`, {
|
||||
method: 'POST',
|
||||
headers: authHeaders(jwt),
|
||||
body: JSON.stringify({ body }),
|
||||
});
|
||||
}
|
||||
|
||||
const pg = () => new Client({ host: 'localhost', port: 55432, user: 'eventsnap_test', password: 'eventsnap_test', database: 'eventsnap_test' });
|
||||
const pg = () =>
|
||||
new Client({
|
||||
host: 'localhost',
|
||||
port: 55432,
|
||||
user: 'eventsnap_test',
|
||||
password: 'eventsnap_test',
|
||||
database: 'eventsnap_test',
|
||||
});
|
||||
|
||||
async function truncate(adminJwt) {
|
||||
await fetch(`${BASE}/api/v1/admin/__truncate`, { method: 'POST', headers: authHeaders(adminJwt) });
|
||||
await fetch(`${BASE}/api/v1/admin/__truncate`, {
|
||||
method: 'POST',
|
||||
headers: authHeaders(adminJwt),
|
||||
});
|
||||
}
|
||||
async function patchConfig(adminJwt, patch) {
|
||||
await fetch(`${BASE}/api/v1/admin/config`, { method: 'PATCH', headers: authHeaders(adminJwt), body: JSON.stringify(patch) });
|
||||
await fetch(`${BASE}/api/v1/admin/config`, {
|
||||
method: 'PATCH',
|
||||
headers: authHeaders(adminJwt),
|
||||
body: JSON.stringify(patch),
|
||||
});
|
||||
}
|
||||
|
||||
// ---- SEED ----
|
||||
@@ -54,9 +96,27 @@ console.log('[seed] admin login + reset');
|
||||
let admin = await adminLogin();
|
||||
await truncate(admin);
|
||||
admin = await adminLogin();
|
||||
await patchConfig(admin, { rate_limits_enabled: 'false', upload_rate_enabled: 'false', feed_rate_enabled: 'false', export_rate_enabled: 'false', join_rate_enabled: 'false', quota_enabled: 'false', storage_quota_enabled: 'false', upload_count_quota_enabled: 'false' });
|
||||
await patchConfig(admin, {
|
||||
rate_limits_enabled: 'false',
|
||||
upload_rate_enabled: 'false',
|
||||
feed_rate_enabled: 'false',
|
||||
export_rate_enabled: 'false',
|
||||
join_rate_enabled: 'false',
|
||||
quota_enabled: 'false',
|
||||
storage_quota_enabled: 'false',
|
||||
upload_count_quota_enabled: 'false',
|
||||
});
|
||||
|
||||
const guests = ['Anna Bauer', 'Lukas Weber', 'Mia Schulz', 'Jonas Fischer', 'Emma Wagner', 'Ben Hoffmann', 'Sophie Klein', 'Paul Richter'];
|
||||
const guests = [
|
||||
'Anna Bauer',
|
||||
'Lukas Weber',
|
||||
'Mia Schulz',
|
||||
'Jonas Fischer',
|
||||
'Emma Wagner',
|
||||
'Ben Hoffmann',
|
||||
'Sophie Klein',
|
||||
'Paul Richter',
|
||||
];
|
||||
const accounts = {};
|
||||
for (const g of guests) accounts[g] = await joinGuest(g);
|
||||
console.log('[seed] joined', guests.length, 'guests');
|
||||
@@ -94,13 +154,23 @@ await comment(accounts['Ben Hoffmann'].jwt, ids[1], 'Was ein Abend!');
|
||||
console.log('[seed] likes + comments done');
|
||||
|
||||
// Make one guest a host so /host renders populated
|
||||
await fetch(`${BASE}/api/v1/host/users/${accounts['Anna Bauer'].user_id}/role`, { method: 'PATCH', headers: authHeaders(admin), body: JSON.stringify({ role: 'host' }) });
|
||||
await fetch(`${BASE}/api/v1/host/users/${accounts['Anna Bauer'].user_id}/role`, {
|
||||
method: 'PATCH',
|
||||
headers: authHeaders(admin),
|
||||
body: JSON.stringify({ role: 'host' }),
|
||||
});
|
||||
|
||||
// Wait for compression to finish so previews render
|
||||
const c = pg(); await c.connect();
|
||||
const c = pg();
|
||||
await c.connect();
|
||||
for (let t = 0; t < 40; t++) {
|
||||
const r = await c.query(`SELECT COUNT(*)::int AS n FROM upload WHERE compression_status <> 'done' AND deleted_at IS NULL`);
|
||||
if (r.rows[0].n === 0) { console.log('[seed] compression done'); break; }
|
||||
const r = await c.query(
|
||||
`SELECT COUNT(*)::int AS n FROM upload WHERE compression_status <> 'done' AND deleted_at IS NULL`
|
||||
);
|
||||
if (r.rows[0].n === 0) {
|
||||
console.log('[seed] compression done');
|
||||
break;
|
||||
}
|
||||
await new Promise((res) => setTimeout(res, 500));
|
||||
}
|
||||
await c.end();
|
||||
@@ -113,17 +183,20 @@ const shot = async (label, theme, who, route, prep) => {
|
||||
const page = await ctx.newPage();
|
||||
// Seed localStorage on the origin
|
||||
await page.goto(`${BASE}/join`, { waitUntil: 'domcontentloaded' });
|
||||
await page.evaluate(({ jwt, pin, uid, name, theme, mode }) => {
|
||||
localStorage.setItem('eventsnap_theme', theme);
|
||||
localStorage.setItem('eventsnap_data_mode', mode);
|
||||
if (jwt) {
|
||||
localStorage.setItem('eventsnap_jwt', jwt);
|
||||
localStorage.setItem('eventsnap_pin', pin);
|
||||
localStorage.setItem('eventsnap_user_id', uid);
|
||||
localStorage.setItem('eventsnap_display_name', name);
|
||||
}
|
||||
localStorage.setItem('eventsnap_guide_seen', '1');
|
||||
}, { jwt: who?.jwt, pin: who?.pin, uid: who?.user_id, name: who?.name, theme, mode: 'saver' });
|
||||
await page.evaluate(
|
||||
({ jwt, pin, uid, name, theme, mode }) => {
|
||||
localStorage.setItem('eventsnap_theme', theme);
|
||||
localStorage.setItem('eventsnap_data_mode', mode);
|
||||
if (jwt) {
|
||||
localStorage.setItem('eventsnap_jwt', jwt);
|
||||
localStorage.setItem('eventsnap_pin', pin);
|
||||
localStorage.setItem('eventsnap_user_id', uid);
|
||||
localStorage.setItem('eventsnap_display_name', name);
|
||||
}
|
||||
localStorage.setItem('eventsnap_guide_seen', '1');
|
||||
},
|
||||
{ jwt: who?.jwt, pin: who?.pin, uid: who?.user_id, name: who?.name, theme, mode: 'saver' }
|
||||
);
|
||||
await page.goto(`${BASE}${route}`, { waitUntil: 'domcontentloaded' });
|
||||
await page.waitForTimeout(1200);
|
||||
if (prep) await prep(page);
|
||||
@@ -141,10 +214,17 @@ for (const theme of ['light', 'dark']) {
|
||||
await shot('01-join', theme, null, '/join');
|
||||
await shot('02-feed-list', theme, hostWho, '/feed');
|
||||
await shot('03-feed-grid', theme, hostWho, '/feed', async (p) => {
|
||||
await p.getByLabel('Rasteransicht').click().catch(() => {});
|
||||
await p
|
||||
.getByLabel('Rasteransicht')
|
||||
.click()
|
||||
.catch(() => {});
|
||||
});
|
||||
await shot('04-lightbox', theme, hostWho, '/feed', async (p) => {
|
||||
await p.locator('img').first().click().catch(() => {});
|
||||
await p
|
||||
.locator('img')
|
||||
.first()
|
||||
.click()
|
||||
.catch(() => {});
|
||||
await p.waitForTimeout(500);
|
||||
});
|
||||
await shot('05-account', theme, hostWho, '/account');
|
||||
|
||||
Reference in New Issue
Block a user