You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			80 lines
		
	
	
		
			2.5 KiB
		
	
	
	
		
			TypeScript
		
	
			
		
		
	
	
			80 lines
		
	
	
		
			2.5 KiB
		
	
	
	
		
			TypeScript
		
	
| import { describe, it, expect, beforeAll, afterAll } from 'bun:test';
 | |
| import { Database } from 'bun:sqlite';
 | |
| import { mkdtempSync, rmSync } from 'fs';
 | |
| import { tmpdir } from 'os';
 | |
| import { join } from 'path';
 | |
| import { startWebServer } from './helpers/server';
 | |
| import { initializeDatabase, ensureUserExists } from '../../src/db';
 | |
| 
 | |
| async function sha256Hex(input: string): Promise<string> {
 | |
| 	const enc = new TextEncoder().encode(input);
 | |
| 	const buf = await crypto.subtle.digest('SHA-256', enc);
 | |
| 	const bytes = new Uint8Array(buf);
 | |
| 	return Array.from(bytes)
 | |
| 		.map((b) => b.toString(16).padStart(2, '0'))
 | |
| 		.join('');
 | |
| }
 | |
| 
 | |
| function toIsoSql(d = new Date()): string {
 | |
| 	return d.toISOString().replace('T', ' ').replace('Z', '');
 | |
| }
 | |
| 
 | |
| describe('Web UI - /app/preferences', () => {
 | |
| 	const userId = '34600123456';
 | |
| 	let dbPath: string;
 | |
| 	let server: Awaited<ReturnType<typeof startWebServer>> | null = null;
 | |
| 	let tmpDir: string;
 | |
| 
 | |
| 	beforeAll(async () => {
 | |
| 		tmpDir = mkdtempSync(join(tmpdir(), 'webtest-'));
 | |
| 		dbPath = join(tmpDir, 'tasks.db');
 | |
| 
 | |
| 		// Inicializar DB en archivo (como en prod)
 | |
| 		const db = new Database(dbPath);
 | |
| 		initializeDatabase(db);
 | |
| 		ensureUserExists(userId, db);
 | |
| 
 | |
| 		// Crear sesión válida
 | |
| 		const sid = 'sid-test-pref-ui';
 | |
| 		const hash = await sha256Hex(sid);
 | |
| 		const now = new Date();
 | |
| 		const nowIso = toIsoSql(now);
 | |
| 		const expIso = toIsoSql(new Date(now.getTime() + 60 * 60 * 1000)); // +1h
 | |
| 
 | |
| 		db.prepare(`
 | |
| 			INSERT INTO web_sessions (session_hash, user_id, created_at, last_seen_at, expires_at)
 | |
| 			VALUES (?, ?, ?, ?, ?)
 | |
| 		`).run(hash, userId, nowIso, nowIso, expIso);
 | |
| 		db.close();
 | |
| 
 | |
| 		// Arrancar web apuntando a este DB
 | |
| 		server = await startWebServer({
 | |
| 			port: 19110,
 | |
| 			env: { DB_PATH: dbPath, TZ: 'UTC' }
 | |
| 		});
 | |
| 	});
 | |
| 
 | |
| 	afterAll(async () => {
 | |
| 		try { await server?.stop(); } catch {}
 | |
| 		try { rmSync(tmpDir, { recursive: true, force: true }); } catch {}
 | |
| 	});
 | |
| 
 | |
| 	it('renderiza el formulario con valores por defecto y muestra próximo recordatorio', async () => {
 | |
| 		const sid = 'sid-test-pref-ui';
 | |
| 		const res = await fetch(`${server!.baseUrl}/app/preferences`, {
 | |
| 			headers: { Cookie: `sid=${sid}` }
 | |
| 		});
 | |
| 		expect(res.status).toBe(200);
 | |
| 		const html = await res.text();
 | |
| 
 | |
| 		expect(html).toContain('Preferencias de recordatorios');
 | |
| 		// control de frecuencia (radio) con opción 'off' presente
 | |
| 		expect(html).toMatch(/<input[^>]+type="radio"[^>]+name="freq"[^>]+value="off"/);
 | |
| 		// input type="time" con valor por defecto
 | |
| 		expect(html).toContain('type="time"');
 | |
| 		expect(html).toContain('08:30');
 | |
| 		// bloque de "Próximo recordatorio"
 | |
| 		expect(html).toContain('Próximo recordatorio');
 | |
| 	});
 | |
| });
 |