> ## Documentation Index
> Fetch the complete documentation index at: https://omniloy.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Testing de tu integración

> Estrategias y patrones para testear integraciones del SDK de SofIA en tu aplicación

Esta guía cubre cómo testear tu integración del SDK de SofIA, desde verificar la configuración básica hasta automatizar tests en pipelines CI/CD.

## Resumen de estrategia de testing

| Nivel                    | Qué testear                                                                  | Herramientas             |
| ------------------------ | ---------------------------------------------------------------------------- | ------------------------ |
| **Verificación manual**  | El componente renderiza, las props son aceptadas, los logs de debug aparecen | Browser DevTools         |
| **Tests unitarios**      | Funciones de callback, transformaciones de datos, validación de templates    | Vitest, Jest             |
| **Tests de integración** | Montaje de componentes, paso de props, manejo de eventos                     | Testing Library, Cypress |
| **Tests E2E**            | Flujo completo desde transcripción hasta reporte                             | Playwright, Cypress      |

## Checklist de verificación manual

Antes de escribir tests automatizados, verifica lo básico con `debug="true"`:

<Steps>
  <Step title="El componente renderiza">
    Abre tu página y confirma que el widget de SofIA aparece. Revisa la consola buscando `[Sofia SDK] Configuration Error` — si está ausente, las props son válidas.
  </Step>

  <Step title="El template se carga">
    Busca `[Sofia SDK] Settings - Template loaded: {n} fields` en la consola. Si `n` coincide con tu cantidad esperada de campos, el template se parseó correctamente.
  </Step>

  <Step title="El botón de generar aparece">
    Si tanto `template` como `templateid` están configurados, el botón de generar debería ser visible. Si falta, revisa los logs de validación de template.
  </Step>

  <Step title="handleReport se ejecuta">
    Haz clic en Generar después de una conversación y verifica que tu callback `handleReport` recibe datos. Loguea la salida con `JSON.stringify(report, null, 2)`.
  </Step>
</Steps>

## Testing unitario de callbacks

Testea tus funciones de callback independientemente del SDK. Estos tests verifican que tu aplicación procesa correctamente los datos que SofIA entrega.

### Testing de handleReport

```javascript theme={null}
import { describe, it, expect, vi } from 'vitest';

// El handler de reportes de tu aplicación
function processReport(report) {
  if (!report || Object.keys(report).length === 0) {
    throw new Error('Reporte vacío recibido');
  }

  return {
    diagnosis: report.diagnostico_principal || null,
    symptoms: report.sintomas || [],
    timestamp: new Date().toISOString(),
  };
}

describe('processReport', () => {
  it('debería extraer diagnóstico del reporte', () => {
    const mockReport = {
      diagnostico_principal: 'Diabetes Mellitus Tipo 2',
      sintomas: ['poliuria', 'polidipsia', 'fatiga'],
    };

    const result = processReport(mockReport);

    expect(result.diagnosis).toBe('Diabetes Mellitus Tipo 2');
    expect(result.symptoms).toHaveLength(3);
    expect(result.timestamp).toBeDefined();
  });

  it('debería manejar campos opcionales faltantes', () => {
    const mockReport = {
      diagnostico_principal: 'Hipertensión',
    };

    const result = processReport(mockReport);

    expect(result.diagnosis).toBe('Hipertensión');
    expect(result.symptoms).toEqual([]);
  });

  it('debería lanzar error con reporte vacío', () => {
    expect(() => processReport({})).toThrow('Reporte vacío recibido');
  });
});
```

### Testing de validación de template

```javascript theme={null}
import { describe, it, expect } from 'vitest';

function isValidTemplate(template) {
  try {
    const schema = typeof template === 'string' ? JSON.parse(template) : template;
    return (
      schema.$schema === 'http://json-schema.org/draft-07/schema#' &&
      schema.type === 'object' &&
      schema.properties &&
      Object.keys(schema.properties).length > 0
    );
  } catch {
    return false;
  }
}

describe('isValidTemplate', () => {
  it('debería aceptar JSON Schema Draft-07 válido', () => {
    const template = JSON.stringify({
      $schema: 'http://json-schema.org/draft-07/schema#',
      title: 'test',
      type: 'object',
      properties: {
        diagnostico: { type: 'string' },
      },
    });

    expect(isValidTemplate(template)).toBe(true);
  });

  it('debería rechazar esquema sin properties', () => {
    const template = JSON.stringify({
      $schema: 'http://json-schema.org/draft-07/schema#',
      type: 'object',
      properties: {},
    });

    expect(isValidTemplate(template)).toBe(false);
  });

  it('debería rechazar JSON inválido', () => {
    expect(isValidTemplate('{invalido')).toBe(false);
  });
});
```

## Testing de integración

### Testing de montaje del componente (Vanilla JS)

```javascript theme={null}
import { describe, it, expect, beforeEach, afterEach } from 'vitest';

describe('Montaje del SDK de SofIA', () => {
  let container;

  beforeEach(() => {
    container = document.createElement('div');
    document.body.appendChild(container);
  });

  afterEach(() => {
    container.remove();
  });

  it('debería montar con props requeridas', async () => {
    container.innerHTML = `
      <sofia-sdk
        apikey="test-key"
        userid="doctor-1"
        patientid="paciente-1"
      ></sofia-sdk>
    `;

    const sofia = container.querySelector('sofia-sdk');
    expect(sofia).not.toBeNull();
  });

  it('debería aceptar callback handleReport', async () => {
    container.innerHTML = '<sofia-sdk></sofia-sdk>';
    const sofia = container.querySelector('sofia-sdk');

    const handleReport = vi.fn();
    sofia.handleReport = handleReport;

    expect(sofia.handleReport).toBe(handleReport);
  });
});
```

### Testing con React

```jsx theme={null}
import { render, screen } from '@testing-library/react';
import { useRef, useEffect } from 'react';
import { describe, it, expect, vi } from 'vitest';

function SofiaWrapper({ onReport, template, templateId }) {
  const ref = useRef(null);

  useEffect(() => {
    if (ref.current) {
      ref.current.handleReport = onReport;
    }
  }, [onReport]);

  return (
    <sofia-sdk
      ref={ref}
      apikey="test-key"
      userid="doctor-1"
      patientid="paciente-1"
      template={template}
      templateid={templateId}
    />
  );
}

describe('SofiaWrapper', () => {
  it('debería renderizar sin errores', () => {
    const handleReport = vi.fn();
    render(<SofiaWrapper onReport={handleReport} />);

    // El componente renderiza sin lanzar excepción
    expect(document.querySelector('sofia-sdk')).not.toBeNull();
  });

  it('debería asignar callback handleReport', () => {
    const handleReport = vi.fn();
    render(<SofiaWrapper onReport={handleReport} />);

    const sofia = document.querySelector('sofia-sdk');
    expect(sofia.handleReport).toBe(handleReport);
  });
});
```

### Testing con Angular

```typescript theme={null}
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { SofiaComponent } from './sofia.component';

describe('SofiaComponent', () => {
  let component: SofiaComponent;
  let fixture: ComponentFixture<SofiaComponent>;

  beforeEach(async () => {
    await TestBed.configureTestingModule({
      declarations: [SofiaComponent],
      schemas: [CUSTOM_ELEMENTS_SCHEMA], // Requerido para web components
    }).compileComponents();

    fixture = TestBed.createComponent(SofiaComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

  it('debería crearse', () => {
    expect(component).toBeTruthy();
  });

  it('debería tener el elemento sofia-sdk en el template', () => {
    const compiled = fixture.nativeElement;
    expect(compiled.querySelector('sofia-sdk')).not.toBeNull();
  });
});
```

## Mockear el SDK para CI/CD

En entornos CI donde el SDK no puede conectarse a servidores reales, mockea el web component para testear tu lógica de integración:

```javascript theme={null}
// test/mocks/sofia-sdk-mock.js

class MockSofiaSDK extends HTMLElement {
  constructor() {
    super();
    this._handleReport = null;
  }

  set handleReport(fn) {
    this._handleReport = fn;
  }

  get handleReport() {
    return this._handleReport;
  }

  // Simular la entrega de un reporte para testing.
  // El SDK real entrega los reportes llamando a la propiedad handleReport —
  // no emite un evento DOM — así que el mock hace lo mismo.
  simulateReport(report) {
    if (this._handleReport) {
      this._handleReport(report);
    }
  }
}

// Registrar mock antes de los tests
if (!customElements.get('sofia-sdk')) {
  customElements.define('sofia-sdk', MockSofiaSDK);
}
```

**Usando el mock en tests:**

```javascript theme={null}
import './mocks/sofia-sdk-mock.js';
import { describe, it, expect, vi } from 'vitest';

describe('Procesamiento de reportes con mock del SDK', () => {
  it('debería procesar reporte simulado', () => {
    const container = document.createElement('div');
    container.innerHTML = '<sofia-sdk></sofia-sdk>';
    document.body.appendChild(container);

    const sofia = container.querySelector('sofia-sdk');
    const handleReport = vi.fn();
    sofia.handleReport = handleReport;

    // Simular que el SDK genera un reporte
    sofia.simulateReport({
      diagnostico_principal: 'Bronquitis aguda',
      sintomas: ['tos', 'fiebre'],
    });

    expect(handleReport).toHaveBeenCalledWith({
      diagnostico_principal: 'Bronquitis aguda',
      sintomas: ['tos', 'fiebre'],
    });

    container.remove();
  });
});
```

## Testing de la entrega de reportes

<Info>
  **SofIA entrega los datos mediante propiedades de callback, no eventos DOM.** Los reportes llegan cuando el SDK llama a la propiedad `handleReport` que asignas (`sofia.handleReport = fn`) — el SDK **no** emite eventos DOM `handle-report`/`set-is-open`/`set-get-last-report`. Testea la ruta del callback, no `addEventListener`.
</Info>

Asigna tu callback como propiedad y verifica que recibe el reporte:

```javascript theme={null}
import { describe, it, expect, vi } from 'vitest';
import './mocks/sofia-sdk-mock.js';

describe('entrega de reporte vía propiedad de callback', () => {
  it('debería llamar a handleReport con el reporte', () => {
    const container = document.createElement('div');
    container.innerHTML = '<sofia-sdk></sofia-sdk>';
    document.body.appendChild(container);

    const sofia = container.querySelector('sofia-sdk');
    const handleReport = vi.fn();
    sofia.handleReport = handleReport;

    // Simular que el SDK entrega un reporte (helper del mock)
    sofia.simulateReport({ diagnostico: 'Test' });

    expect(handleReport).toHaveBeenCalledWith({ diagnostico: 'Test' });

    container.remove();
  });
});
```

<Tip>
  El único CustomEvent DOM que el SDK realmente emite es `sofia:transcriber-url-changed` (con `detail: { url }`), disparado cuando se resuelve la URL del transcriptor. Rara vez lo necesitas, pero puede observarse con un `addEventListener('sofia:transcriber-url-changed', ...)` estándar.
</Tip>

## Configuración del entorno de testing

### Configuración de Vitest

```javascript theme={null}
// vitest.config.js
import { defineConfig } from 'vitest/config';

export default defineConfig({
  test: {
    environment: 'jsdom', // Requerido para APIs del DOM
    globals: true,
    setupFiles: ['./test/setup.js'],
  },
});
```

### Archivo de setup

```javascript theme={null}
// test/setup.js

// Registrar mock del SDK antes de todos los tests
import './mocks/sofia-sdk-mock.js';

// Suprimir warnings de consola del SDK en la salida de tests
const originalWarn = console.warn;
console.warn = (...args) => {
  if (args[0]?.includes?.('[Sofia SDK]')) return;
  originalWarn(...args);
};
```

<Tip>
  Enfoca tus tests automatizados en **tu** código de integración (callbacks, transformaciones de datos, actualizaciones de UI), no en los internos del SDK. El SDK es testeado internamente con más de 160 casos de test. Tus tests deberían verificar que tu aplicación procesa correctamente los datos que SofIA entrega.
</Tip>

## Próximos pasos

1. [Solución de Problemas](/sofia/es/sdk/troubleshooting) — soluciones para problemas comunes
2. [Referencia de Errores](/sofia/es/sdk/error-reference) — catálogo completo de mensajes de error del SDK
3. [Guía de Migración](/sofia/es/sdk/migration) — actualizar de v0.x a v1.0
