Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .cargo/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Propagate Linux libc++ link flags when running cargo from repo root.
[target.x86_64-unknown-linux-gnu]
rustflags = ["-C", "link-arg=-lc++", "-C", "link-arg=-lc++abi"]

[target.aarch64-unknown-linux-gnu]
rustflags = ["-C", "link-arg=-lc++", "-C", "link-arg=-lc++abi"]
30 changes: 30 additions & 0 deletions .cursorrules
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Aturan Pengembangan Tauri & Rust — ZipLoom

## IPC (Rust ↔ Frontend)

1. **Registrasi IPC wajib:** Setiap fungsi `#[tauri::command]` HARUS ditambahkan ke `tauri::generate_handler![...]` di `src-tauri/src/lib.rs`. Jangan biarkan command tidak terdaftar.
2. **Serde & penamaan:** JavaScript memakai camelCase, Rust memakai snake_case. Struct yang dikirim ke/dari frontend WAJIB `#[derive(Serialize, Deserialize)]` + `#[serde(rename_all = "camelCase")]`.
3. **Jangan blokir UI:** Operasi I/O file, komputasi berat (ZIP, forensic scan, hash), atau network WAJIB `async fn` dengan `tauri::async_runtime::spawn_blocking` — logika sync di fungsi `*_sync`.
4. **Penanganan error:** Jangan `.unwrap()` / `.expect()` di dalam command. Selalu kembalikan `Result<T, String>`.
5. **Frontend invoke:** Semua panggilan lewat `src/lib/tauri.js` — wrapper sudah memiliki `try/catch` + `console.error`. Jangan panggil `@tauri-apps/api/core` `invoke` langsung dari komponen.

## Debugging

- Saat app berjalan: klik kanan → Inspect Element, atau `Cmd+Option+I` (Mac) / `Ctrl+Shift+I` (Win/Linux).
- Cek tab **Console** untuk error merah seperti `command 'xxx' not found` (command belum didaftarkan di handler).

## Testing

- Rust E2E: `npm run test:e2e` — workflow compress/inspect/extract.
- GUI smoke: `npm run test:gui` — Playwright + mock IPC; gagal jika ada console error.
- Full suite: `npm run test:all`.

## File penting

| Area | Path |
|------|------|
| Commands | `src-tauri/src/commands.rs` |
| Handler registry | `src-tauri/src/lib.rs` |
| IPC wrapper | `src/lib/tauri.js` |
| GUI tests | `tests/gui-smoke.mjs` |
| Playwright config | `playwright.config.mjs` |
5 changes: 4 additions & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,11 @@ jobs:
- name: Test ysf-core
run: cargo test --manifest-path src-tauri/crates/ysf-core/Cargo.toml --locked -- --test-threads=2

- name: IPC coverage check
run: npm run test:ipc

- name: Test Rust
run: cargo test --manifest-path src-tauri/Cargo.toml --locked
run: cargo test --manifest-path src-tauri/Cargo.toml --tests --locked

- name: Build Rust
run: cargo build --manifest-path src-tauri/Cargo.toml --locked
Expand Down
11 changes: 10 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,17 @@ jobs:
run: npm run build
- name: Build Rust
run: cargo build --manifest-path src-tauri/Cargo.toml --locked
- name: IPC coverage check
run: npm run test:ipc

- name: Test Rust
run: cargo test --manifest-path src-tauri/Cargo.toml --locked
run: cargo test --manifest-path src-tauri/Cargo.toml --tests --locked

- name: Install Playwright Chromium
run: npx playwright install chromium --with-deps

- name: GUI smoke tests
run: npm run test:gui

- name: npm audit
run: npm audit --audit-level=moderate
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,10 +139,11 @@ npm run screenshots # Regenerate README screenshots

| Suite | Coverage |
|-------|----------|
| E2E (Rust) | 7/7 — compress → inspect → extract, password ZIP roundtrip |
| GUI smoke | 15/15 — tabs, theme toggle, compress, extract, inspect scan/hash/export |
| IPC coverage | Static — all frontend `invoke()` commands registered in Rust |
| E2E (Rust) | 12/12 — compress/inspect/extract, forensic scan, hash, preview, IPC registry |
| GUI smoke | 20/20 — tabs, password ZIP, preview, about centering, no console errors |

CI runs on **ubuntu**, **macos**, and **windows** on every push to `main`.
CI runs on **ubuntu**, **macos**, and **windows** on every push to `main`, including Playwright GUI smoke tests on Ubuntu.

---

Expand Down
37 changes: 33 additions & 4 deletions docs/DEVELOPER.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,10 @@ ziploom/
| `npm run tauri:build` | Production installer (DMG / NSIS / deb / AppImage) |
| `npm run icons` | Regenerate `src-tauri/icons/*` from `logo.svg` |
| `npm run build` | Frontend only (Vite) |
| `npm run test:e2e` | 7 Rust integration tests |
| `npm run test:gui` | 15 Playwright UI smoke tests |
| `npm run test:all` | E2E + GUI |
| `npm run test:ipc` | Static check: frontend `invoke()` ⊆ `generate_handler!` |
| `npm run test:e2e` | 12 Rust integration tests (workflow + IPC registry) |
| `npm run test:gui` | 20 Playwright UI smoke tests (incl. console error check) |
| `npm run test:all` | IPC + E2E + GUI |
| `npm run screenshots` | Regenerate `screenshots/*.png` |

## Rust tests
Expand All @@ -84,6 +85,34 @@ cargo test --manifest-path src-tauri/crates/ysf-core/Cargo.toml --locked

E2E temp dirs use per-test unique paths (`AtomicU64` counter) to avoid parallel CI races.

## Debugging Tauri (DevTools)

While the app runs (`npm run tauri:dev`):

1. **Right-click** the window → **Inspect Element**, or press `Cmd+Option+I` (macOS) / `Ctrl+Shift+I` (Windows/Linux).
2. Open the **Console** tab.
3. Look for red errors — common ones:
- `command 'xxx' not found` → command missing from `generate_handler!` in `lib.rs`
- `[ZipLoom IPC] xxx failed:` → logged by `src/lib/tauri.js` wrapper

Project rules for AI assistants live in `.cursorrules` at the repo root.

## GUI testing (Playwright)

`tests/gui-smoke.mjs` launches Vite preview, mocks Tauri IPC, and asserts:

- All tabs render and primary flows work (compress, extract, inspect, about)
- **No console errors** during the run

```bash
npm run test:gui # after npm run build
npm run test:all # Rust E2E + GUI
```

CI (`ci.yml`) runs `test:gui` on every push to `main`.

Heavy Tauri commands run on a background thread via `spawn_blocking` — see `run_blocking()` in `commands.rs`. Sync implementations are `*_sync` and used by Rust E2E tests.

## macOS local setup

1. **Xcode Command Line Tools** — `xcode-select --install`
Expand All @@ -110,7 +139,7 @@ Linux release links `libc++` for `unrar_sys` — see `src-tauri/.cargo/config.to

| Workflow | Trigger | Jobs |
|----------|---------|------|
| `ci.yml` | push/PR `main` | Secret scan (gitleaks CLI), ysf-core tests, ZipLoom build+test |
| `ci.yml` | push/PR `main` | Secret scan, ysf-core tests, ZipLoom build+test, **GUI smoke** |
| `build.yml` | push/PR `main` | Matrix: ubuntu / macos / windows |
| `audit.yml` | schedule + Cargo changes | `cargo audit`, SBOM |

Expand Down
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@
"package:releases": "node scripts/package-releases.mjs",
"icons": "tauri icon src-tauri/icons/logo.svg -o src-tauri/icons",
"test:gui": "npm run build && node tests/gui-smoke.mjs",
"test:e2e": "cargo test --manifest-path src-tauri/Cargo.toml --test e2e_workflow_test",
"test:all": "npm run test:e2e && npm run test:gui",
"test:ipc": "node tests/ipc-coverage.mjs",
"test:e2e": "cargo test --manifest-path src-tauri/Cargo.toml --tests --locked",
"test:all": "npm run test:ipc && npm run test:e2e && npm run test:gui",
"screenshots": "npm run build && node tests/capture-screenshots.mjs"
},
"dependencies": {
Expand Down
10 changes: 10 additions & 0 deletions playwright.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/** @type {import('@playwright/test').PlaywrightTestConfig} */
export default {
testDir: "tests",
testMatch: "gui-smoke.mjs",
timeout: 120_000,
use: {
headless: true,
viewport: { width: 900, height: 600 },
},
};
Loading
Loading