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

# Testing hugs

> Testing a hug's definition, its page with mock_host, and in the browser with cliq hug dev.

Hugs

| What | How |
| - | - |
| The definition — params, rules, summary, upload slots | Plain unit tests |
| The page — what it draws and what it sends | `mock_host` from `@getcliqio/hug-frontend/testing`, in a DOM test environment |
| The page in a browser | `cliq hug dev` |
| The whole Hug — the agent and an answer | Run the team locally; answer on the page, or with cliqd's API |

`cliq hug new` scaffolds a test and a `test` script (`vitest run --environment happy-dom`).

The blocks below are abridged from the examples' tests ([`examples/hugs`](https://github.com/getcliqio/cliq/tree/main/examples/hugs)); each example has a `hug.test.ts` and a `page.test.ts`.

***

## The definition

```ts hug.test.ts (abridged) theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
import { describe, expect, it } from 'vitest';
import review_batch from './hug';

const PARAMS = { company: 'ACME', documents: [{ id: 'lease', name: 'Lease' }, { id: 'payslip', name: 'Payslip' }] };

function params() {
    const p = review_batch.check_params(PARAMS);
    if (!p.ok) throw new Error('params');
    return p.value;
}

describe('review-batch', () => {
    it('a rejection needs a note', () => {
        const missing = review_batch.check({ verdicts: [{ id: 'lease', ok: true }, { id: 'payslip', ok: false }] }, params());
        expect(missing).toMatchObject({ ok: false, problems: [{ path: 'verdicts[1].note' }] });
    });
    it('says how many were OK', () => {
        expect(review_batch.summary({ verdicts: [{ id: 'lease', ok: true }, { id: 'payslip', ok: false, note: 'x' }] }, params())).toBe('1 of 2 OK');
    });
    it('its evidence is an upload slot', () => {
        expect(review_batch.files(params())).toEqual([{ name: 'evidence', accept: ['image/*', '.pdf', '.txt'], max_bytes: 5_000_000, required: false }]);
    });
});
```

The agent checks answers with this same definition, so these tests are the rules that count.

## The page — `mock_host`

`mock_host` stands in for the Hub page: it answers the page's messages, records what it sends, and plays the
person's part.

```ts theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
import { mount_hug } from '@getcliqio/hug-frontend';
import { mock_host } from '@getcliqio/hug-frontend/testing';

it('asks for a note when a document is not OK', async () => {
    const host = mock_host({ definition: review_batch, params: PARAMS });
    mount_hug(review_batch, { connect: { transport: host.transport }, initial, submit, edit });
    await host.flush();

    // …click "Not OK" on the second document in the DOM, then:
    await host.flush();
    expect(host.last_values()).toMatchObject({ valid: false, submit: { label: 'Send verdicts' } });
});
```

`mock_host(options)`:

| Option | |
| - | - |
| `definition` | Fills the Hug's name, title and upload slots |
| `params`, `attachments`, `files` | What the Hug was asked |
| `mode`, `status`, `mine`, `viewing`, `draft` | Where the page starts (answering, viewing an answer, an ended Hug) |
| `viewer`, `progress`, `theme`, `locale` | The rest of what the host tells the page |
| `upload(key)` | What the person picks: a file reference, or an error code (`upload_cancelled`, …) |
| `read(ref)` | A file's bytes as a `Blob`, or an error code (`read_denied`, …) |

The host it returns:

| | |
| - | - |
| `transport` | Pass to `mount_hug`'s `connect`, or `connect({ transport })` |
| `sent` | Every message the page sent that a host would take |
| `issues` | What a host would refuse — a message that breaks the bridge's rules (a Submit label over 40 characters, values over 256 KB, an unknown type) — with why; those aren't acted on. `expect(host.issues).toEqual([])` catches them |
| `last_values()` | Its latest answer state: `values`, `valid`, `problems`, `submit`, `summary` |
| `downloads`, `links` | What it asked to download and open |
| `height()` | The frame height it asked for |
| `flush()` | Wait for pending messages |
| `submit()` | Press Submit — then the page shows the answer read-only. Refused, as on the Hub, when the page says the answer isn't valid (the page gets its problems back) |
| `change_answer()` | Press **Change answer** |
| `close(status?)`, `update({ progress, expires_at })` | The Hug ends, or its progress changes |

### Testing the real page

`mock_host` can drive your actual `src/main.ts`: point `mount_hug` at it with `vi.mock`, then import the page.

```ts page.test.ts (abridged) theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
import { beforeAll, expect, it, vi } from 'vitest';
import { mock_host, type MockHost } from '@getcliqio/hug-frontend/testing';
import triage_list from './hug';
import params from './params.json';

const h = vi.hoisted(() => ({ host: null as unknown as MockHost }));
vi.mock('@getcliqio/hug-frontend', async (original) => {
    const m = await original<typeof import('@getcliqio/hug-frontend')>();
    return { ...m, mount_hug: (d, o) => m.mount_hug(d, { ...o, connect: { transport: h.host.transport } }) };
});

beforeAll(async () => {
    document.body.innerHTML = '<div id="app"></div>';
    h.host = mock_host({ definition: triage_list, params });
    await import('./src/main');
    await h.host.flush();
});

it('starts with nothing triaged', () => {
    expect(h.host.last_values()).toMatchObject({ valid: false, submit: { label: 'Triage 6 more' } });
});
```

For a page on the runtime API, mock `connect` the same way; for React, wrap `HugRoot` to pass `connect`. Every
[example](https://docs.getcliq.io/hugs/overview.md#examples) has a `page.test.ts`.

Test view mode by starting there: `mock_host({ definition, params, mode: 'view', viewing: { values } })`.

## In the browser — `cliq hug dev`

```bash theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
cliq hug dev hugs/review-batch --params params.json --attachments sample/
cliq hug dev hugs/review-batch --params params.json --view answer.json
```

`--attachments` gives the folder's files the ids `dev-file-0`, `dev-file-1`, … in name order — use them in the
sample params. The hug on cliqd's local Hug page — no run, no Hug — rebuilt and reloaded as you edit, with a panel showing what it
sends: values, valid, problems, the Submit label, the summary, uploads, reads and links. Try every state: an empty
answer, an invalid one, the view.

The panel also has an **accessibility check**: [axe](https://github.com/dequelabs/axe-core) runs inside the hug's frame
after it draws and after each change, against WCAG 2.2 A and AA and axe's best practices, in the theme your browser
prefers. Each problem shows how serious it is, the rule, where it is (inside a kit element: `cliq-field » input`) and
a link explaining the fix. Rules about the whole page — landmarks, the page's heading, skip links — are left out:
those are the host's.

**Errors in the hug** lists what your own code threw, promises it left rejected, files that didn't load, and what the
frame's sandbox blocked (a `fetch`, an outside image or font — see [Security](https://docs.getcliq.io/hugs/security.md) for what to do instead),
with the file and line and the first lines of the stack. Both run only in `cliq hug dev`, from a script cliqd adds to the
frame; a real Hug's frame never loads it.

## The whole Hug

Run the team with a local cliqd: `cliq run` opens the Hug's page. To answer from a test or script — including
answers the page wouldn't allow, to check that the agent refuses them:

```bash theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
curl -s -X POST http://127.0.0.1:4900/v1/hugs/respond -H 'content-type: application/json' \
  -d '{"hug_id":"<id>","values":{"verdicts":[{"id":"lease","ok":false}]},"responder":"test"}'
```

The run's log says the answer couldn't be used, and the Hug stays open. The `hug_id` is in the run's `hug.opened`
event.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.