> ## 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 your integration

> Strategies and patterns for testing SofIA SDK integrations in your application

This guide covers how to test your SofIA SDK integration, from verifying basic setup to automating tests in CI/CD pipelines.

## Testing strategy overview

| Level                   | What to test                                                  | Tools                    |
| ----------------------- | ------------------------------------------------------------- | ------------------------ |
| **Manual verification** | Component renders, props are accepted, debug logs appear      | Browser DevTools         |
| **Unit tests**          | Callback functions, data transformations, template validation | Vitest, Jest             |
| **Integration tests**   | Component mounting, prop passing, event handling              | Testing Library, Cypress |
| **E2E tests**           | Full workflow from transcription to report                    | Playwright, Cypress      |

## Manual verification checklist

Before writing automated tests, verify the basics with `debug="true"`:

<Steps>
  <Step title="Component renders">
    Open your page and confirm the SofIA widget appears. Check the console for `[Sofia SDK] Configuration Error` — if absent, props are valid.
  </Step>

  <Step title="Template loads">
    Look for `[Sofia SDK] Settings - Template loaded: {n} fields` in the console. If `n` matches your expected field count, the template parsed correctly.
  </Step>

  <Step title="Generate button appears">
    If both `template` and `templateid` are set, the generate button should be visible. If missing, check template validation logs.
  </Step>

  <Step title="handleReport fires">
    Click Generate after a conversation and verify your `handleReport` callback receives data. Log the output with `JSON.stringify(report, null, 2)`.
  </Step>
</Steps>

## Unit testing callbacks

Test your callback functions independently from the SDK. These tests verify that your application correctly processes the data SofIA delivers.

### Testing handleReport

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

// Your application's report handler
function processReport(report) {
  if (!report || Object.keys(report).length === 0) {
    throw new Error('Empty report received');
  }

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

describe('processReport', () => {
  it('should extract diagnosis from report', () => {
    const mockReport = {
      primary_diagnosis: 'Type 2 Diabetes Mellitus',
      symptoms: ['polyuria', 'polydipsia', 'fatigue'],
    };

    const result = processReport(mockReport);

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

  it('should handle missing optional fields', () => {
    const mockReport = {
      primary_diagnosis: 'Hypertension',
    };

    const result = processReport(mockReport);

    expect(result.diagnosis).toBe('Hypertension');
    expect(result.symptoms).toEqual([]);
  });

  it('should throw on empty report', () => {
    expect(() => processReport({})).toThrow('Empty report received');
  });
});
```

### Testing template validation

```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('should accept valid JSON Schema Draft-07', () => {
    const template = JSON.stringify({
      $schema: 'http://json-schema.org/draft-07/schema#',
      title: 'test',
      type: 'object',
      properties: {
        diagnosis: { type: 'string' },
      },
    });

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

  it('should reject schema without properties', () => {
    const template = JSON.stringify({
      $schema: 'http://json-schema.org/draft-07/schema#',
      type: 'object',
      properties: {},
    });

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

  it('should reject invalid JSON', () => {
    expect(isValidTemplate('{invalid')).toBe(false);
  });
});
```

## Integration testing

### Testing component mounting (Vanilla JS)

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

describe('SofIA SDK mounting', () => {
  let container;

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

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

  it('should mount with required props', async () => {
    container.innerHTML = `
      <sofia-sdk
        apikey="test-key"
        userid="doctor-1"
        patientid="patient-1"
      ></sofia-sdk>
    `;

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

  it('should accept handleReport callback', 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 with 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="patient-1"
      template={template}
      templateid={templateId}
    />
  );
}

describe('SofiaWrapper', () => {
  it('should render without crashing', () => {
    const handleReport = vi.fn();
    render(<SofiaWrapper onReport={handleReport} />);

    // Component renders without throwing
    expect(document.querySelector('sofia-sdk')).not.toBeNull();
  });

  it('should assign handleReport callback', () => {
    const handleReport = vi.fn();
    render(<SofiaWrapper onReport={handleReport} />);

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

### Testing with 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], // Required for web components
    }).compileComponents();

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

  it('should create', () => {
    expect(component).toBeTruthy();
  });

  it('should have sofia-sdk element in template', () => {
    const compiled = fixture.nativeElement;
    expect(compiled.querySelector('sofia-sdk')).not.toBeNull();
  });
});
```

## Mocking the SDK for CI/CD

In CI environments where the SDK cannot connect to real servers, mock the web component to test your integration logic:

```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;
  }

  // Simulate report generation for testing.
  // The real SDK delivers reports by calling the handleReport property —
  // it does not emit a DOM event — so the mock does the same.
  simulateReport(report) {
    if (this._handleReport) {
      this._handleReport(report);
    }
  }
}

// Register mock before tests
if (!customElements.get('sofia-sdk')) {
  customElements.define('sofia-sdk', MockSofiaSDK);
}
```

**Using the mock in tests:**

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

describe('Report processing with mock SDK', () => {
  it('should process simulated report', () => {
    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;

    // Simulate the SDK generating a report
    sofia.simulateReport({
      primary_diagnosis: 'Acute bronchitis',
      symptoms: ['cough', 'fever'],
    });

    expect(handleReport).toHaveBeenCalledWith({
      primary_diagnosis: 'Acute bronchitis',
      symptoms: ['cough', 'fever'],
    });

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

## Testing report delivery

<Info>
  **SofIA delivers data through callback properties, not DOM events.** Reports arrive by the SDK calling the `handleReport` property you assign (`sofia.handleReport = fn`) — the SDK does **not** emit `handle-report`/`set-is-open`/`set-get-last-report` DOM events. Test the callback path, not `addEventListener`.
</Info>

Assign your callback as a property and assert it receives the report:

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

describe('report delivery via callback property', () => {
  it('should call handleReport with the report', () => {
    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;

    // Simulate the SDK delivering a report (mock helper)
    sofia.simulateReport({ diagnosis: 'Test' });

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

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

<Tip>
  The only DOM CustomEvent the SDK actually emits is `sofia:transcriber-url-changed` (with `detail: { url }`), fired when the transcriber URL is resolved. You rarely need it, but it can be observed with a standard `addEventListener('sofia:transcriber-url-changed', ...)`.
</Tip>

## Test environment configuration

### Vitest configuration

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

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

### Setup file

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

// Register mock SDK before all tests
import './mocks/sofia-sdk-mock.js';

// Suppress console warnings from SDK in test output
const originalWarn = console.warn;
console.warn = (...args) => {
  if (args[0]?.includes?.('[Sofia SDK]')) return;
  originalWarn(...args);
};
```

<Tip>
  Focus your automated tests on **your** integration code (callbacks, data transformations, UI updates), not on the SDK internals. The SDK is tested internally with 160+ test cases. Your tests should verify that your application correctly processes the data SofIA delivers.
</Tip>

## Next steps

1. [Troubleshooting](/sofia/en/sdk/troubleshooting) — solutions for common issues
2. [Error Reference](/sofia/en/sdk/error-reference) — complete catalog of SDK error messages
3. [Migration Guide](/sofia/en/sdk/migration) — upgrade from v0.x to v1.0
