diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 3bb6dbe..9566f0f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -53,6 +53,15 @@ jobs: permissions: checks: write + rustfmt_check: + name: Formatting for Rust backend + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + - run: rustup update stable && rustup default stable && rustup component add rustfmt + # Source-only formatting check (no compile / no frontend build needed). Run `cargo fmt` to fix. + - run: cargo fmt --all --check + client_test: name: Tests and linting for React client runs-on: ubuntu-latest diff --git a/AGENTS.md b/AGENTS.md index b8e9d38..3694a6d 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -201,7 +201,9 @@ the working-directory-aware tools. | Build | `cargo build` | | Test | `cargo test` | | Lint | `cargo clippy` | +| Format (check / fix) | `cargo fmt --check` / `cargo fmt` (default rustfmt) | | Run full app (dev) | `cargo tauri dev` | +| Run a 2nd dev instance alongside the installed release | `cargo run -- --multi` (or `WIDGETSACK_MULTI=1`) — skips the single-instance lock + isolates config to `/multi` | | Release build → `target/release/widgetsack.exe` | `cargo tauri build` | > ⚠️ **Build order gotcha:** Tauri embeds `client/build` (`frontendDist`), so the frontend diff --git a/Cargo.lock b/Cargo.lock index c101ad9..1f0cdba 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5130,7 +5130,7 @@ dependencies = [ [[package]] name = "widgetsack" -version = "0.0.47" +version = "0.0.48" dependencies = [ "fontdb", "futures-util", diff --git a/client/.eslintrc.cjs b/client/.eslintrc.cjs index 6a6f96d..a5cd659 100644 --- a/client/.eslintrc.cjs +++ b/client/.eslintrc.cjs @@ -22,5 +22,13 @@ module.exports = { }, settings: { react: { version: 'detect' } - } + }, + overrides: [ + { + // Test code may use non-null assertions on values it has just constructed / knows are defined + // (e.g. asserting on a Patch's `monitor`). Production code keeps the strict rule. + files: ['**/*.test.ts', '**/*.test.tsx'], + rules: { '@typescript-eslint/no-non-null-assertion': 'off' } + } + ] }; diff --git a/client/.gitignore b/client/.gitignore index 2293605..f6f40f0 100644 --- a/client/.gitignore +++ b/client/.gitignore @@ -18,3 +18,4 @@ build/* /blob-report /.playwright-mcp /playwright/.cache +coverage/ diff --git a/client/.prettierignore b/client/.prettierignore index d99d3de..3a4b0c6 100644 --- a/client/.prettierignore +++ b/client/.prettierignore @@ -20,3 +20,4 @@ build /blob-report /.playwright-mcp /playwright/.cache +coverage/ diff --git a/client/e2e/helpers.ts b/client/e2e/helpers.ts index 3392a2e..65d993e 100644 --- a/client/e2e/helpers.ts +++ b/client/e2e/helpers.ts @@ -49,12 +49,24 @@ export async function previewTemplate(page: Page, name: string): Promise { await page.getByRole('button', { name, exact: true }).click(); } -/** Add a widget from the Inspector palette (Layouts section) and return the now-selected host. */ +/** + * Add a widget from the Inspector palette (Layouts section) and return the now-selected host. + * `type` is the palette LABEL (e.g. "Gauge", "Analog Clock"). The palette button's accessible name + * is "