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.
		
		
		
		
		
			
		
			
				
	
	
		
			96 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			TypeScript
		
	
			
		
		
	
	
			96 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			TypeScript
		
	
| import { describe, it, expect, afterAll } from 'bun:test';
 | |
| import Database from 'bun:sqlite';
 | |
| import { startWebServer } from './helpers/server';
 | |
| import { createTempDb } from './helpers/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('API - /api/integrations/feeds', () => {
 | |
|   const PORT = 19123;
 | |
|   const BASE = `http://127.0.0.1:${PORT}`;
 | |
|   const USER = '34600123456';
 | |
|   const GROUP = '123@g.us';
 | |
|   const SID = 'sid-test-123';
 | |
| 
 | |
|   const tmp = createTempDb();
 | |
|   const db: any = tmp.db as Database;
 | |
| 
 | |
|   // Sembrar datos mínimos
 | |
|   db.exec(`INSERT OR IGNORE INTO users (id) VALUES ('${USER}')`);
 | |
|   db.exec(`INSERT OR IGNORE INTO groups (id, community_id, name, active) VALUES ('${GROUP}', 'comm1', 'Group 1', 1)`);
 | |
|   db.exec(`INSERT OR IGNORE INTO allowed_groups (group_id, status, discovered_at, updated_at) VALUES ('${GROUP}', 'allowed', '${toIsoSql()}', '${toIsoSql()}')`);
 | |
|   db.exec(`INSERT OR IGNORE INTO group_members (group_id, user_id, is_admin, is_active, first_seen_at, last_seen_at) VALUES ('${GROUP}', '${USER}', 0, 1, '${toIsoSql()}', '${toIsoSql()}')`);
 | |
| 
 | |
|   // Crear sesión web válida (cookie sid)
 | |
|   const sidHashPromise = sha256Hex(SID);
 | |
|   const serverPromise = startWebServer({
 | |
|     port: PORT,
 | |
|     env: {
 | |
|       DB_PATH: tmp.path,
 | |
|       WEB_BASE_URL: BASE
 | |
|     }
 | |
|   });
 | |
| 
 | |
|   let server: Awaited<typeof serverPromise> | null = null;
 | |
| 
 | |
|   afterAll(async () => {
 | |
|     try { await server?.stop(); } catch {}
 | |
|     try { tmp.cleanup(); } catch {}
 | |
|   });
 | |
| 
 | |
|   it('GET: autogenera y devuelve URLs para personal, grupo y aggregate; POST rotate rota el de grupo', async () => {
 | |
|     server = await serverPromise;
 | |
| 
 | |
|     const sidHash = await sidHashPromise;
 | |
|     // Insertar sesión después de lanzar el server (mismo archivo)
 | |
|     db.exec(`
 | |
|       INSERT OR REPLACE INTO web_sessions (id, user_id, session_hash, created_at, last_seen_at, expires_at)
 | |
|       VALUES ('sess-1', '${USER}', '${sidHash}', '${toIsoSql()}', '${toIsoSql()}', '${toIsoSql(new Date(Date.now() + 2 * 60 * 60 * 1000))}')
 | |
|     `);
 | |
| 
 | |
|     // GET feeds
 | |
|     const res = await fetch(`${BASE}/api/integrations/feeds`, {
 | |
|       headers: { cookie: `sid=${SID}` }
 | |
|     });
 | |
|     expect(res.status).toBe(200);
 | |
|     const body = await res.json();
 | |
|     // Personal URL presente (recién creada)
 | |
|     expect(typeof body.personal).toBe('object');
 | |
|     expect(typeof body.personal.url === 'string' && body.personal.url.endsWith('.ics')).toBe(true);
 | |
|     // Aggregate URL presente (recién creada)
 | |
|     expect(typeof body.aggregate).toBe('object');
 | |
|     expect(typeof body.aggregate.url === 'string' && body.aggregate.url.endsWith('.ics')).toBe(true);
 | |
|     // Grupo autogenerado con URL presente
 | |
|     const groupFeed = (body.groups || []).find((g: any) => g.groupId === GROUP);
 | |
|     expect(groupFeed).toBeDefined();
 | |
|     expect(typeof groupFeed.url === 'string' && groupFeed.url.endsWith('.ics')).toBe(true);
 | |
| 
 | |
|     const previousGroupUrl = groupFeed.url;
 | |
| 
 | |
|     // POST rotate para el grupo
 | |
|     const resRotate = await fetch(`${BASE}/api/integrations/feeds/rotate`, {
 | |
|       method: 'POST',
 | |
|       headers: {
 | |
|         'content-type': 'application/json',
 | |
|         cookie: `sid=${SID}`
 | |
|       },
 | |
|       body: JSON.stringify({ type: 'group', groupId: GROUP })
 | |
|     });
 | |
|     expect(resRotate.status).toBe(200);
 | |
|     const bodyRotate = await resRotate.json();
 | |
|     expect(typeof bodyRotate.url === 'string' && bodyRotate.url.endsWith('.ics')).toBe(true);
 | |
|     expect(bodyRotate.url).not.toBe(previousGroupUrl);
 | |
|   });
 | |
| });
 |