From 8bdf1c9be33ceedf80b7f56a56e197a967a1fe17 Mon Sep 17 00:00:00 2001 From: yaroslav k Date: Sat, 15 Aug 2026 14:57:35 +0300 Subject: [PATCH] rewrite README; replace example e2e spec with a smoke test README is now project-specific (features, stack, dev commands, docs). The Playwright spec checks home/inventories/wiki render and asserts no console errors. --- README.md | 110 +++++++++++++++++----------------- end2end/tests/example.spec.ts | 9 --- end2end/tests/smoke.spec.ts | 56 +++++++++++++++++ 3 files changed, 110 insertions(+), 65 deletions(-) delete mode 100644 end2end/tests/example.spec.ts create mode 100644 end2end/tests/smoke.spec.ts diff --git a/README.md b/README.md index 99ecfcb..2aebf90 100644 --- a/README.md +++ b/README.md @@ -1,72 +1,70 @@ - - - Leptos Logo - +# aex -# Leptos Starter Template +A D&D 5e character sheet and campaign dashboard for a text-based play-by-post +game. The UI is in Russian. -This is a template for use with the [Leptos](https://github.com/leptos-rs/leptos) web framework and the [cargo-leptos](https://github.com/akesson/cargo-leptos) tool. +## What works today -## Creating your template repo +- Campaign header: name, in-game date steppers, session counter +- Character sidebar: portrait, names, class, level, XP, hit points with + temp HP bar, hit dice, death saves, spell slots +- Inventories page (`/inv`): personal and party-common inventories, + currency per denomination, item rows with quantity and weight steppers, + move between inventories, remove +- Bundled 5e.tools item data (~5k items) with fuzzy search components + (search is not mounted on a page yet) -If you don't have `cargo-leptos` installed you can install it with +State is mock data: nothing is persisted, and several buttons and pages are +stubs. The phased plan to fix that is in [ROADMAP.md](./ROADMAP.md). -`cargo install cargo-leptos --locked` +## Tech stack -Then run +- Rust, edition 2024, nightly toolchain (pinned in `rust-toolchain.toml`) +- Leptos 0.8 SSR (actix-web) + client-side hydration +- `reactive_stores` for the reactive state model +- SCSS (`style/main.scss`), compiled by dart-sass +- Playwright for end-to-end tests -`cargo leptos new --git leptos-rs/start-actix` +## Development -to generate a new project template (you will be prompted to enter a project name). +Prerequisites: `cargo-leptos`, dart-sass, and the `wasm32-unknown-unknown` +target. The nightly toolchain installs itself via `rust-toolchain.toml`. -`cd {projectname}` - -to go to your newly created project. - -Of course, you should explore around the project structure, but the best place to start with your application code is in `src/app.rs`. - -## Running your project - -`cargo leptos watch` -By default, you can access your local project at `http://localhost:3000` - -## Installing Additional Tools - -By default, `cargo-leptos` uses `nightly` Rust, `cargo-generate`, and `sass`. If you run into any trouble, you may need to install one or more of these tools. - -1. `rustup toolchain install nightly --allow-downgrade` - make sure you have Rust nightly -2. `rustup target add wasm32-unknown-unknown` - add the ability to compile Rust to WebAssembly -3. `cargo install cargo-generate` - install `cargo-generate` binary (should be installed automatically in future) -4. `npm install -g sass` - install `dart-sass` (should be optional in future) - -## Executing a Server on a Remote Machine Without the Toolchain -After running a `cargo leptos build --release` the minimum files needed are: - -1. The server binary located in `target/server/release` -2. The `site` directory and all files within located in `target/site` - -Copy these files to your remote server. The directory structure should be: -```text -leptos_start -site/ -``` -Set the following environment variables (updating for your project as needed): ```sh -export LEPTOS_OUTPUT_NAME="leptos_start" -export LEPTOS_SITE_ROOT="site" -export LEPTOS_SITE_PKG_DIR="pkg" -export LEPTOS_SITE_ADDR="127.0.0.1:3000" -export LEPTOS_RELOAD_PORT="3001" +cargo install cargo-leptos +cargo leptos watch # dev server with hot reload +# open http://127.0.0.1:3000 ``` -Finally, run the server binary. -## Notes about CSR and Trunk: -Although it is not recommended, you can also run your project without server integration using the feature `csr` and `trunk serve`: +Other commands: -`trunk serve --open --features csr` +```sh +cargo leptos build --release # production build +cargo leptos serve # dev server without the watcher +cargo check --no-default-features --features ssr --bin aex +cargo check --no-default-features --features hydrate --lib +cargo check --target wasm32-unknown-unknown --no-default-features --features hydrate --lib +``` -This may be useful for integrating external tools which require a static site, e.g. `tauri`. +## Tests -## Licensing +End-to-end smoke tests live in `end2end/` (Playwright). With the dev server +running on port 3000: -This template itself is released under the Unlicense. You should replace the LICENSE for your own application with an appropriate license if you plan to release it publicly. +```sh +cd end2end +npm install +npx playwright test +``` + +or let cargo-leptos manage the server: `cargo leptos end2end`. + +## Project docs + +- [ARCHITECTURE.md](./ARCHITECTURE.md) — how the code is organized +- [ROADMAP.md](./ROADMAP.md) — the phased plan to MVP +- [MODERNIZE.md](./MODERNIZE.md) — dependency and idiom cleanup list + +## License + +Public domain (Unlicense), see [LICENSE](./LICENSE). diff --git a/end2end/tests/example.spec.ts b/end2end/tests/example.spec.ts deleted file mode 100644 index a461f35..0000000 --- a/end2end/tests/example.spec.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { test, expect } from "@playwright/test"; - -test("homepage has title and links to intro page", async ({ page }) => { - await page.goto("http://localhost:3000/"); - - await expect(page).toHaveTitle("Welcome to Leptos"); - - await expect(page.locator("h1")).toHaveText("Welcome to Leptos!"); -}); diff --git a/end2end/tests/smoke.spec.ts b/end2end/tests/smoke.spec.ts new file mode 100644 index 0000000..fe9bc20 --- /dev/null +++ b/end2end/tests/smoke.spec.ts @@ -0,0 +1,56 @@ +import { test, expect, type Page } from "@playwright/test"; + +const BASE = "http://localhost:3000"; + +// Collects browser console errors and page errors for the duration of a test. +function trackErrors(page: Page): string[] { + const errors: string[] = []; + page.on("console", (msg) => { + if (msg.type() === "error") { + errors.push(msg.text()); + } + }); + page.on("pageerror", (err) => { + errors.push(String(err)); + }); + return errors; +} + +test("home page: campaign name, version, nav", async ({ page }) => { + const errors = trackErrors(page); + await page.goto(`${BASE}/`); + + await expect(page.locator("#campaign-name")).toHaveValue("В Поисках Дмитрия Шардалина"); + await expect(page.locator(".version")).toContainText("aex"); + await expect(page.locator(".main-nav a")).toHaveCount(3); + await expect(page.locator(".main-nav")).toContainText("Персонаж"); + await expect(page.locator(".main-nav")).toContainText("Инвентарь"); + await expect(page.locator(".main-nav")).toContainText("Информация"); + + expect(errors).toEqual([]); +}); + +test("inventories page: personal and common sections", async ({ page }) => { + const errors = trackErrors(page); + await page.goto(`${BASE}/inv`); + + await expect(page.locator(".inventory-personal")).toHaveCount(1); + await expect(page.locator(".inventory-common")).toHaveCount(1); + // each section has one balance block with five currency inputs + await expect(page.locator(".inventory-personal .balance .numput")).toHaveCount(5); + await expect(page.locator(".inventory-common .balance .numput")).toHaveCount(5); + // and at least one item row each + await expect(page.locator(".inventory-personal .item").first()).toBeVisible(); + await expect(page.locator(".inventory-common .item").first()).toBeVisible(); + + expect(errors).toEqual([]); +}); + +test("wiki page: stub renders", async ({ page }) => { + const errors = trackErrors(page); + await page.goto(`${BASE}/wiki`); + + await expect(page.locator("body")).toContainText("books"); + + expect(errors).toEqual([]); +});