import { afterAll, beforeAll, describe, expect, test } from 'bun:test'; import { createServer, type ViteDevServer } from 'vite'; import { faqs, faqSchemaMainEntity, watchTogetherFaqAnswer } from '../src/lib/content/faqs'; import { csr, prerender } from '../src/routes/privacy/+page'; let vite: ViteDevServer; let renderedPrivacyHead: string; let renderedPrivacyHtml: string; let privacySource: string; beforeAll(async () => { vite = await createServer({ root: process.cwd(), appType: 'custom', server: { middlewareMode: true }, }); const [{ default: privacyPage }, { render }] = await Promise.all([ vite.ssrLoadModule('/src/routes/privacy/+page.svelte'), vite.ssrLoadModule('svelte/server'), ]); const rendered = render(privacyPage); renderedPrivacyHead = rendered.head; renderedPrivacyHtml = rendered.body; privacySource = await Bun.file('src/routes/privacy/+page.svelte').text(); }, 90_000); afterAll(async () => { await vite?.close(); }, 30_000); function visibleText(html: string): string { return html .replace(/<[^>]+>/g, ' ') .replaceAll('&', '&') .replaceAll(''', "'") .replace(/\s+/g, ' ') .trim(); } describe('privacy page', () => { test('remains a prerendered, server-rendered route', () => { expect(prerender).toBe(true); expect(csr).toBe(false); expect(renderedPrivacyHead).toContain('Privacy Policy - Plezy'); expect(renderedPrivacyHead).toContain(' { for (const heading of [ 'Overview', 'Data on your device', 'Connections and third parties', 'Optional Plezy services', 'Your choices', 'Retention and security', 'Contact and changes', ]) { expect(renderedPrivacyHtml).toContain(`>${heading}`); } expect(renderedPrivacyHtml.match(/
{ const text = visibleText(renderedPrivacyHtml); expect(text).not.toMatch(/\brepositor(?:y|ies)\b/i); expect(text).not.toMatch(/repository-verified/i); expect(text).toContain('We do not sell personal data or use it for advertising'); expect(text).toContain('access tokens and other sign-in data'); expect(text).toContain('may contain a server access credential'); expect(text).toContain('does not carry the media stream or your media-server credentials'); expect(text).toContain('Support-log uploads are always explicit'); expect(text).toContain('up to 90 days'); expect(text).toContain('retrieved for three days'); expect(text).toContain('no more than three hours'); expect(renderedPrivacyHtml).toContain('rel="noopener noreferrer"'); }); test('keeps the Watch Together disclosure aligned with visible FAQ content', () => { const faqIndex = faqs.findIndex((faq) => faq.id === 'watch-together'); expect(faqIndex).toBeGreaterThanOrEqual(0); expect(faqs[faqIndex]!.answer).toBe(watchTogetherFaqAnswer); expect(faqSchemaMainEntity[faqIndex]!.acceptedAnswer.text).toBe(watchTogetherFaqAnswer); expect(watchTogetherFaqAnswer).toContain('server and media identifiers'); expect(watchTogetherFaqAnswer).toContain('does not relay the media stream'); expect(watchTogetherFaqAnswer).toContain('custom relay'); }); });