# Pengujian

Dua lapis: **tes unit** yang cepat dan bisa diulang, dan **uji main** di Ralystudioo.

## Tes unit dengan `createTestHost`

`@ralyoo/sdk/testing` menjalankan game terhadap runtime dan jembatan platform yang asli, tanpa browser, tanpa relay, tanpa HP. Validasi layout, audio, storage, jeda, dan `end`/`exit` berlaku persis seperti di host.

```ts
import { createTestHost } from '@ralyoo/sdk/testing';
import { expect, it } from 'vitest';
import { createGame } from './game.ts';

it('pemain pertama yang menekan A menang', async () => {
  const host = createTestHost(createGame(viewPalsu), { players: 3, seed: 7 });
  await host.start(); // preload → "GAS!" → onStart

  host.tap(2, 'A'); // tekan lalu lepas
  expect(host.ended?.scores).toEqual({ 2: 1 });
  expect(host.errors).toEqual([]);
});
```

Waktu hanya maju kalau tes memintanya, dan pesan diantar seketika, jadi tes tidak pernah menunggu dan hasilnya selalu sama.

|                                                     |                                                           |
| --------------------------------------------------- | --------------------------------------------------------- |
| `await host.start()`                                | Memasang game, menjalankan `preload`, lalu `onStart`      |
| `host.frame(ms?)`, `host.frames(n, ms?)`            | Memajukan satu atau `n` frame (bawaan 1/60 detik)         |
| `host.press/release/tap(player, tombol)`            | Tombol jalur cepat                                        |
| `host.stick(player, { lx, ly })`                    | Joystick, −1..1                                           |
| `host.event(player, { widget, type, value })`       | Event widget: tombol lain, `vote`, `page`                 |
| `host.disconnect(player)`, `host.reconnect(player)` | HP putus dan kembali                                      |
| `host.pause()`, `host.resume()`                     | Menu host                                                 |
| `host.layout(player)`                               | Layout yang sedang tampil di HP itu                       |
| `host.ended`, `host.exited`                         | Hasil `ctx.end` dan `ctx.exit`                            |
| `host.audio`, `host.mixes`                          | Semua panggilan `ctx.audio`                               |
| `host.errors`                                       | Error dari game. Tes yang lulus biasanya ingin ini kosong |
| `host.storage`                                      | Isi `ctx.storage`                                         |

Opsi: `players` (jumlah atau daftar pemain), `seed`, `locale`, `reducedMotion`, `storage` (isi awal).

### Pisahkan aturan dari tampilan

Tes berjalan di Node, tanpa DOM dan tanpa WebGL. Template memisahkan game jadi dua:

- `src/game.ts`: aturan dan alur. Menerima sebuah `View` dan tidak menyentuh DOM atau Pixi.
- `src/view.ts`: tampilan yang sesungguhnya.

Tes memberi `createGame` tampilan palsu yang hanya mencatat:

```ts
const frames: ViewState[] = [];
const viewPalsu: View = { mount() {}, render: (state) => frames.push(state) };
```

Kalau kamu ingin mengetes tampilan DOM juga, jalankan Vitest dengan `environment: 'happy-dom'`.

### Yang layak dites

- Aturan skor dan kondisi menang.
- Layout yang dikirim ke tiap HP, terutama yang berbeda per pemain.
- Pemain putus di tengah giliran, dan kembali.
- Jeda: tidak ada yang bergerak selama menu terbuka.
- Jumlah pemain terkecil dan terbesar yang kamu dukung.

## Uji main di Ralystudioo

Yang tidak bisa dijawab tes unit: apakah terasa enak, terbaca, dan lancar.

- 2, 3, dan 4 pemain.
- **Latency** 150 ms: apakah kontrol masih terasa adil?
- **Disconnect** di saat genting.
- **Reduced motion**.
- HP sungguhan lewat `ralystudioo dev --lan`: ukuran tombol dan orientasi baru terasa di tangan.
- HUD performa: fps dan frame di atas 50 ms.

Lihat [Ralystudioo](ralystudioo.md).

## Sebelum mengunggah

```sh
npm test && npm run lint && npm run pack
```

`lint` dan `pack` menjalankan pemeriksaan yang sama dengan registry, jadi yang lolos di sini lolos saat diunggah.
