# tauri-plugin-phyto
A Tauri plugin that runs an HTTP automation server inside a Tauri app so
[Phyto](https://github.com/coniferous-dev/phyto) (an end-to-end testing
framework for Tauri) can drive it.
## What it does
When the plugin is initialized, it:
1. Starts an HTTP server on port `9876` (configurable) bound to `0.0.0.0`.
2. Polls the webview until it has navigated past `about:blank`, the Tauri
IPC bridge is available, and the in-page Phyto harness (injected by
`@phyto/vite-plugin`) has loaded.
3. Forwards `POST /command` requests to the in-page harness via
`window.__phyto_harness__.execute()`, then sends the structured result
back over HTTP.
4. Exposes `GET /health` for readiness probing.
The plugin is intended for **test builds only**. It listens on `0.0.0.0` and
runs arbitrary JavaScript supplied by the test driver — do not enable it in
production builds.
## Usage
The plugin is intended for test builds only. The recommended integration
puts everything behind a Cargo feature (called `e2e` by convention) so
production builds neither compile the plugin nor reference its capability.
### 1. Declare the feature
In `src-tauri/Cargo.toml`:
```toml
[features]
e2e = ["tauri-plugin-phyto"]
[dependencies]
tauri-plugin-phyto = { version = "0.1", optional = true }
[build-dependencies]
tauri-plugin-phyto = { version = "0.1", default-features = false, features = ["build"] }
```
The `[build-dependencies]` entry pulls in just the `build` helper module
(`std`-only, no Tauri tree on the host compile).
### 2. Sync the capability in `build.rs`
Tauri capabilities are filesystem-scanned at build time and `tauri-build`
rejects any capability that references an unregistered plugin. The
`sync_capability` helper writes `capabilities/phyto.json` when the `e2e`
feature is on and deletes it when off — so the same source tree builds
cleanly in both modes:
```rust
fn main() {
tauri_plugin_phyto::build::sync_capability();
tauri_build::build();
}
```
For multi-window apps or a non-`e2e` feature name, use the builder form:
```rust
tauri_plugin_phyto::build::SyncCapability::new()
.feature("e2e-test")
.windows(["main", "settings"])
.run();
```
### 3. Register the plugin
Gate the plugin registration on the same feature in your Tauri builder:
```rust
fn main() {
let builder = tauri::Builder::default();
#[cfg(feature = "e2e")]
let builder = builder.plugin(tauri_plugin_phyto::init(Default::default()));
builder
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
```
Then build with `cargo build --features e2e` for test runs and without
the feature for production. The capability file is created/removed
automatically; you should not commit it to source control.
## Configuration
```rust
use tauri_plugin_phyto::PhytoConfig;
tauri::Builder::default()
.plugin(tauri_plugin_phyto::init(PhytoConfig { port: 9876 }))
```
| port | 9876 | Port the HTTP automation server binds to. |
## How it fits together
`tauri-plugin-phyto` is the in-app server half of Phyto. On the other side:
- `@phyto/vite-plugin` (npm) injects the in-page harness into your app's
build output during test runs.
- `@phyto/driver-tauri` (npm) is the Node-side driver that issues
`click` / `type` / `wait-for` commands over this plugin's HTTP socket.
- `phyto` (npm) is the test-authoring DSL.
- `@phyto/cli` (npm) is the orchestrator that builds the app, discovers
tests, and runs each one against a fresh app instance.
See the top-level [Phyto README](https://github.com/coniferous-dev/phyto)
for the full picture.
## Protocol version
The plugin and driver negotiate a `PROTOCOL_VERSION` integer at startup. If
they disagree, the CLI exits with a clear error naming the mismatched
component. Bump this version on breaking wire-format changes only.
## License
[MIT](https://github.com/coniferous-dev/phyto/blob/main/LICENSE)