spa(phase 5, tasks 26-32): reactions, replies, nip-07 kommentare, e2e
Neue Komponenten unter $lib/components/:
- Reactions.svelte: lädt kind:7-Aggregation via loadReactions, rendert
Chips mit Emoji + Count. +/- werden zu 👍/👎 gemappt.
- ReplyItem.svelte: einzelner Kommentar mit Author-Npub-Prefix + Datum.
- ReplyList.svelte: lädt kind:1-Replies, merged mit optimistic-Props
(dedup per id), sortiert chronologisch.
- ReplyComposer.svelte: Textarea + Senden-Button. Nutzt NIP-07-Wrapper
(getPublicKey, signEvent), baut kind:1-Event mit a/e/p-Tags, pusht
via pool.publish() zu allen Read-Relays. Fehlertolerant: zeigt
Hinweis, wenn NIP-07-Extension fehlt.
Integration in PostView: Reactions, Composer, ReplyList unterhalb des
Artikel-Bodys. Optimistisches Reply-Pattern: Composer.onPublished
pushed signed event in PostView-local $state, ReplyList merged mit
fetched events.
Playwright-E2E:
- playwright.config.ts mit Dev-Server-Auto-Start
- home.test.ts: Profil + Beitragsliste sichtbar
- post.test.ts: Titel + Body + Legacy-URL-Redirect
Alle 3 E2E-Tests grün. npm run check: 600 files, 0 errors.
Deploy live auf svelte.joerg-lohrer.de (Phase 5 inklusive).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 17:51:57 +02:00
|
|
|
import { expect, test } from '@playwright/test';
|
|
|
|
|
|
spa: startseite + archiv + impressum + menü + assets für cutover
Startseite (+page.svelte) komplett überarbeitet:
- Hero mit lokalem Profilbild (WebP aus static/, schneller als
kind:0-roundtrip), Begrüßung "Hi Willkommen auf meinem Blog 🤗",
About/Website aus kind:0
- Social-Icons-Leiste (Nostr/Mastodon/Bluesky/LinkedIn/ORCID/Mail)
als inline-SVG, monochrom via currentColor, hover färbt blau
- Nostr-Icon von satscoffee/nostr_icons (outline, CC0), die anderen
stilisiert als vereinfachte Brand-Icons
- Neueste 5 Posts + Archiv-Link
Archiv-Route (/archiv/): alle Posts, nach Jahr gruppiert.
Impressum (/impressum/): static-page, rendert content/impressum.md
(via vite ?raw-import), bleibt aus nostr-feeds draußen. Frontmatter-
parser toleriert trailing-spaces auf --- zeilen.
Menü im Layout: sticky header mit brand + 3 links (Home, Archiv,
Impressum), aktiv-state via akzent-farbe. Footer mit © + Impressum
+ "Nostr-basiert"-hinweis.
Assets: profilbild und favicons aus dem hugo-static (repo-root) nach
app/static/ übernommen, favicon-links in app.html ergänzt.
NIP-05: .well-known/nostr.json in app/static angelegt mit CORS-header
via .htaccess, damit "joerglohrer@joerg-lohrer.de" nach cutover
verifizierbar bleibt.
E2E-Tests angepasst an neue hero/navigation-struktur, 29/29 unit + 4/4
e2e grün.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-18 15:35:05 +02:00
|
|
|
test('Home zeigt Hero (Name + Avatar) und neueste Beiträge', async ({ page }) => {
|
spa(phase 5, tasks 26-32): reactions, replies, nip-07 kommentare, e2e
Neue Komponenten unter $lib/components/:
- Reactions.svelte: lädt kind:7-Aggregation via loadReactions, rendert
Chips mit Emoji + Count. +/- werden zu 👍/👎 gemappt.
- ReplyItem.svelte: einzelner Kommentar mit Author-Npub-Prefix + Datum.
- ReplyList.svelte: lädt kind:1-Replies, merged mit optimistic-Props
(dedup per id), sortiert chronologisch.
- ReplyComposer.svelte: Textarea + Senden-Button. Nutzt NIP-07-Wrapper
(getPublicKey, signEvent), baut kind:1-Event mit a/e/p-Tags, pusht
via pool.publish() zu allen Read-Relays. Fehlertolerant: zeigt
Hinweis, wenn NIP-07-Extension fehlt.
Integration in PostView: Reactions, Composer, ReplyList unterhalb des
Artikel-Bodys. Optimistisches Reply-Pattern: Composer.onPublished
pushed signed event in PostView-local $state, ReplyList merged mit
fetched events.
Playwright-E2E:
- playwright.config.ts mit Dev-Server-Auto-Start
- home.test.ts: Profil + Beitragsliste sichtbar
- post.test.ts: Titel + Body + Legacy-URL-Redirect
Alle 3 E2E-Tests grün. npm run check: 600 files, 0 errors.
Deploy live auf svelte.joerg-lohrer.de (Phase 5 inklusive).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 17:51:57 +02:00
|
|
|
await page.goto('/');
|
spa: startseite + archiv + impressum + menü + assets für cutover
Startseite (+page.svelte) komplett überarbeitet:
- Hero mit lokalem Profilbild (WebP aus static/, schneller als
kind:0-roundtrip), Begrüßung "Hi Willkommen auf meinem Blog 🤗",
About/Website aus kind:0
- Social-Icons-Leiste (Nostr/Mastodon/Bluesky/LinkedIn/ORCID/Mail)
als inline-SVG, monochrom via currentColor, hover färbt blau
- Nostr-Icon von satscoffee/nostr_icons (outline, CC0), die anderen
stilisiert als vereinfachte Brand-Icons
- Neueste 5 Posts + Archiv-Link
Archiv-Route (/archiv/): alle Posts, nach Jahr gruppiert.
Impressum (/impressum/): static-page, rendert content/impressum.md
(via vite ?raw-import), bleibt aus nostr-feeds draußen. Frontmatter-
parser toleriert trailing-spaces auf --- zeilen.
Menü im Layout: sticky header mit brand + 3 links (Home, Archiv,
Impressum), aktiv-state via akzent-farbe. Footer mit © + Impressum
+ "Nostr-basiert"-hinweis.
Assets: profilbild und favicons aus dem hugo-static (repo-root) nach
app/static/ übernommen, favicon-links in app.html ergänzt.
NIP-05: .well-known/nostr.json in app/static angelegt mit CORS-header
via .htaccess, damit "joerglohrer@joerg-lohrer.de" nach cutover
verifizierbar bleibt.
E2E-Tests angepasst an neue hero/navigation-struktur, 29/29 unit + 4/4
e2e grün.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-18 15:35:05 +02:00
|
|
|
// Hero: Name als h1
|
|
|
|
|
await expect(page.getByRole('heading', { level: 1 })).toBeVisible();
|
|
|
|
|
// Hero: Avatar (lokaler fallback oder nostr-profil)
|
|
|
|
|
await expect(page.locator('.hero .avatar')).toBeVisible({ timeout: 15_000 });
|
|
|
|
|
// Neueste-Beiträge-Sektion
|
|
|
|
|
await expect(page.getByRole('heading', { level: 2, name: /Neueste Beiträge/i })).toBeVisible();
|
|
|
|
|
// Mindestens ein Post lädt
|
spa(phase 5, tasks 26-32): reactions, replies, nip-07 kommentare, e2e
Neue Komponenten unter $lib/components/:
- Reactions.svelte: lädt kind:7-Aggregation via loadReactions, rendert
Chips mit Emoji + Count. +/- werden zu 👍/👎 gemappt.
- ReplyItem.svelte: einzelner Kommentar mit Author-Npub-Prefix + Datum.
- ReplyList.svelte: lädt kind:1-Replies, merged mit optimistic-Props
(dedup per id), sortiert chronologisch.
- ReplyComposer.svelte: Textarea + Senden-Button. Nutzt NIP-07-Wrapper
(getPublicKey, signEvent), baut kind:1-Event mit a/e/p-Tags, pusht
via pool.publish() zu allen Read-Relays. Fehlertolerant: zeigt
Hinweis, wenn NIP-07-Extension fehlt.
Integration in PostView: Reactions, Composer, ReplyList unterhalb des
Artikel-Bodys. Optimistisches Reply-Pattern: Composer.onPublished
pushed signed event in PostView-local $state, ReplyList merged mit
fetched events.
Playwright-E2E:
- playwright.config.ts mit Dev-Server-Auto-Start
- home.test.ts: Profil + Beitragsliste sichtbar
- post.test.ts: Titel + Body + Legacy-URL-Redirect
Alle 3 E2E-Tests grün. npm run check: 600 files, 0 errors.
Deploy live auf svelte.joerg-lohrer.de (Phase 5 inklusive).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 17:51:57 +02:00
|
|
|
await expect(page.locator('a.card').first()).toBeVisible({ timeout: 15_000 });
|
|
|
|
|
});
|
spa: startseite + archiv + impressum + menü + assets für cutover
Startseite (+page.svelte) komplett überarbeitet:
- Hero mit lokalem Profilbild (WebP aus static/, schneller als
kind:0-roundtrip), Begrüßung "Hi Willkommen auf meinem Blog 🤗",
About/Website aus kind:0
- Social-Icons-Leiste (Nostr/Mastodon/Bluesky/LinkedIn/ORCID/Mail)
als inline-SVG, monochrom via currentColor, hover färbt blau
- Nostr-Icon von satscoffee/nostr_icons (outline, CC0), die anderen
stilisiert als vereinfachte Brand-Icons
- Neueste 5 Posts + Archiv-Link
Archiv-Route (/archiv/): alle Posts, nach Jahr gruppiert.
Impressum (/impressum/): static-page, rendert content/impressum.md
(via vite ?raw-import), bleibt aus nostr-feeds draußen. Frontmatter-
parser toleriert trailing-spaces auf --- zeilen.
Menü im Layout: sticky header mit brand + 3 links (Home, Archiv,
Impressum), aktiv-state via akzent-farbe. Footer mit © + Impressum
+ "Nostr-basiert"-hinweis.
Assets: profilbild und favicons aus dem hugo-static (repo-root) nach
app/static/ übernommen, favicon-links in app.html ergänzt.
NIP-05: .well-known/nostr.json in app/static angelegt mit CORS-header
via .htaccess, damit "joerglohrer@joerg-lohrer.de" nach cutover
verifizierbar bleibt.
E2E-Tests angepasst an neue hero/navigation-struktur, 29/29 unit + 4/4
e2e grün.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-18 15:35:05 +02:00
|
|
|
|
|
|
|
|
test('Navigation erreicht Archiv und Impressum', async ({ page }) => {
|
|
|
|
|
await page.goto('/');
|
|
|
|
|
await page.getByRole('link', { name: 'Archiv', exact: true }).click();
|
|
|
|
|
await expect(page.getByRole('heading', { level: 1, name: /Archiv/i })).toBeVisible();
|
|
|
|
|
|
|
|
|
|
await page.getByRole('link', { name: 'Impressum', exact: true }).first().click();
|
|
|
|
|
await expect(page.getByRole('heading', { level: 1, name: /Impressum/i })).toBeVisible();
|
|
|
|
|
});
|