110 lines
3.6 KiB
TypeScript
110 lines
3.6 KiB
TypeScript
// Tests fuer PWA-Manifest + Service-Worker
|
|
// Phase 4.2
|
|
|
|
import { describe, it, expect } from 'vitest';
|
|
import { readFileSync, existsSync } from 'node:fs';
|
|
import { join } from 'node:path';
|
|
|
|
const WEBAPP_DIR = join(__dirname, '..', '..', 'webapp');
|
|
|
|
describe('PWA-Manifest', () => {
|
|
const manifestPath = join(WEBAPP_DIR, 'public', 'manifest.webmanifest');
|
|
|
|
it('existiert', () => {
|
|
expect(existsSync(manifestPath)).toBe(true);
|
|
});
|
|
|
|
it('hat alle PWA-Pflichtfelder', () => {
|
|
const manifest = JSON.parse(readFileSync(manifestPath, 'utf-8')) as Record<string, unknown>;
|
|
expect(manifest.name).toBeTruthy();
|
|
expect(manifest.short_name).toBeTruthy();
|
|
expect(manifest.start_url).toBeTruthy();
|
|
expect(manifest.display).toBeTruthy();
|
|
expect(Array.isArray(manifest.icons)).toBe(true);
|
|
});
|
|
|
|
it('verweist auf existierende Icons', () => {
|
|
const manifest = JSON.parse(readFileSync(manifestPath, 'utf-8')) as {
|
|
icons: Array<{ src: string }>;
|
|
};
|
|
for (const icon of manifest.icons) {
|
|
const iconPath = join(WEBAPP_DIR, 'public', icon.src);
|
|
expect(existsSync(iconPath), `Icon fehlt: ${icon.src}`).toBe(true);
|
|
}
|
|
});
|
|
|
|
it('hat standalone display (PWA-faehig)', () => {
|
|
const manifest = JSON.parse(readFileSync(manifestPath, 'utf-8')) as { display: string };
|
|
expect(manifest.display).toBe('standalone');
|
|
});
|
|
});
|
|
|
|
describe('PWA-Icons', () => {
|
|
it('icon-192.svg existiert und ist valides SVG', () => {
|
|
const path = join(WEBAPP_DIR, 'public', 'icon-192.svg');
|
|
expect(existsSync(path)).toBe(true);
|
|
const content = readFileSync(path, 'utf-8');
|
|
expect(content).toContain('<svg');
|
|
expect(content).toContain('viewBox');
|
|
});
|
|
|
|
it('icon-512.svg existiert und ist valides SVG', () => {
|
|
const path = join(WEBAPP_DIR, 'public', 'icon-512.svg');
|
|
expect(existsSync(path)).toBe(true);
|
|
const content = readFileSync(path, 'utf-8');
|
|
expect(content).toContain('<svg');
|
|
expect(content).toContain('viewBox');
|
|
});
|
|
});
|
|
|
|
describe('Service-Worker', () => {
|
|
const swPath = join(WEBAPP_DIR, 'public', 'service-worker.js');
|
|
|
|
it('existiert', () => {
|
|
expect(existsSync(swPath)).toBe(true);
|
|
});
|
|
|
|
it('hat alle Standard-Event-Handler', () => {
|
|
const sw = readFileSync(swPath, 'utf-8');
|
|
expect(sw).toMatch(/addEventListener\(['"]install['"]/);
|
|
expect(sw).toMatch(/addEventListener\(['"]activate['"]/);
|
|
expect(sw).toMatch(/addEventListener\(['"]fetch['"]/);
|
|
});
|
|
|
|
it('hat Background-Sync Handler (Phase 4.3 erweitert)', () => {
|
|
const sw = readFileSync(swPath, 'utf-8');
|
|
expect(sw).toMatch(/addEventListener\(['"]sync['"]/);
|
|
expect(sw).toContain('mindomat-sync');
|
|
});
|
|
|
|
it('definiert CACHE_NAME', () => {
|
|
const sw = readFileSync(swPath, 'utf-8');
|
|
expect(sw).toMatch(/CACHE_NAME\s*=/);
|
|
});
|
|
|
|
it('hat PRECACHE_URLS mit Pflicht-Dateien', () => {
|
|
const sw = readFileSync(swPath, 'utf-8');
|
|
expect(sw).toMatch(/PRECACHE_URLS/);
|
|
expect(sw).toContain("'/'");
|
|
expect(sw).toContain('manifest.webmanifest');
|
|
});
|
|
|
|
it('skippt API-Anfragen vom Caching', () => {
|
|
const sw = readFileSync(swPath, 'utf-8');
|
|
expect(sw).toContain('/api/');
|
|
expect(sw).toMatch(/startsWith\(['"]\/api\/['"]\)/);
|
|
});
|
|
});
|
|
|
|
describe('PWA-Integration in index.html', () => {
|
|
it('referenziert das Manifest', () => {
|
|
const html = readFileSync(join(WEBAPP_DIR, 'index.html'), 'utf-8');
|
|
expect(html).toMatch(/<link[^>]*rel=['"]manifest['"][^>]*href=['"]\/manifest\.webmanifest['"]/);
|
|
});
|
|
|
|
it('registriert den Service-Worker', () => {
|
|
const html = readFileSync(join(WEBAPP_DIR, 'index.html'), 'utf-8');
|
|
expect(html).toMatch(/navigator\.serviceWorker\.register/);
|
|
});
|
|
});
|