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');
});
});