Contributing
Thanks for considering contributing. ferridriver is pre-1.0 and the surface is still moving — small PRs are easier to land than big ones. Open an issue (or a draft PR with the problem statement) before writing significant code so we can agree on the approach.
Repository layout
11 workspace crates plus one example. See Project layout in the README for the full table.
Documentation lives in site/ (rspress) and per-crate
README.md files. Maintainer-only notes live in docs/.
Prerequisites
- Rust nightly (edition 2024), pinned in
rust-toolchain.toml. MSRV (rust-version) is 1.91. just— task runner.cargo install justor use your package manager.- Bun 1.0+ (only for the
ferridriver-nodeNAPI binding and the documentation site). - For the WebKit backend: the Playwright WebKit binary (
ferridriver install webkit,npx playwright install webkit, or setFERRIDRIVER_WEBKIT). - For the BiDi backend: Firefox installed locally.
- Linux:
pkg-config,libclang-dev, and the Chromium runtime dependencies.ferridriver install --with-deps chromiumcovers them.
Building and testing
The Node binding lives outside default-members. To exercise it:
Commit and PR conventions
- Conventional Commits.
feat:,fix:,docs:,refactor:,test:,perf:,ci:,chore:. Optional scope:feat(bdd): …,fix(webkit): …. - No AI attribution. No
Co-Authored-By: Claude, noGenerated byfooters. Commits should read as developer-authored. - One concern per PR. A docs typo and a behavior change don't belong in the same PR.
- Update tests. Behavior change without a test rarely lands.
- Update docs. If you change a CLI flag, an API signature, or a
config key, the matching page in
site/docs/needs an update in the same PR. - Update CHANGELOG.md. It's regenerated via
git-cliffat release time, so well-formed Conventional Commit messages are the unit of changelog input.
Code style
- Nightly Rust toolchain, edition 2024.
- 2-space indent, 120-char line width (see
rustfmt.toml). cargo fmt --allbefore pushing.- Clippy:
correctness/perf/suspicious= deny;style/complexity/pedantic= warn. No#[allow(clippy::...)]suppressions — fix the underlying issue or open a discussion. - No
unsafe_codein non-test crates without explicit justification. - No
expect_used/unwrap_used/todoin non-test code. FxHashMap(rustc-hash) instead ofstd::HashMapfor performance.- No comments narrating WHAT the code does — names already do that. Comments are for the WHY that a reader would miss.
Playwright parity rules
ferridriver tracks Playwright's Page / Locator / BrowserContext
surface. When adding or changing API:
- Read the canonical Playwright TS declaration in
/tmp/playwright/packages/playwright-core/src/client/*.ts(clone the repo into/tmp/playwrightif you don't have it). - Implement in Rust core (
crates/ferridriver/src/) first. - Update the NAPI binding (
crates/ferridriver-node/src/) and verify the regeneratedcrates/ferridriver-node/index.d.tsmatches the intended TS shape. - Update the QuickJS binding (
crates/ferridriver-script/src/bindings/) when the new surface should be reachable from JS / TS BDD steps andrun_script. - Add a per-option integration test that observes a real DOM-side or
protocol-side effect on every backend the API supports. Signatures
alone are not parity — see
CLAUDE.mdfor the lessons-learned that produced this rule.
Documentation
The site is built with rspress. Edit Markdown in
site/docs/ and preview locally:
The CHANGELOG and CONTRIBUTING pages are mirrored from the repo root
via a prebuild script in site/package.json. Edit the root copies,
not the mirrors.
Filing an issue
https://github.com/salamaashoush/ferridriver/issues
Include:
ferridriver --versionrustc --version- OS and architecture
- Output of
ferridriver -vv ...reproducing the failure - A minimal repro (a single
.featurefile or a ~10-line Rust test)
Security
Report vulnerabilities privately to salamaashoush@gmail.com rather than opening a public issue. PGP key on request.
License
By contributing, you agree that your contributions are licensed under the MIT OR Apache-2.0 dual license that covers the rest of the project.